diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 23:13:52 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 23:13:52 +0100 |
| commit | 1ef9f7af25f6afae52decb8280285d2824d69c83 (patch) | |
| tree | 499cf000a0ad847f8cedcc204124ed5f027f1cc4 /drivers | |
| parent | 3a809b602233ed47ae7375b72663c4147853b1c3 (diff) | |
| parent | 85842b61f64cac93d28e129d35193e329d463fd1 (diff) | |
| download | linux-next-history-1ef9f7af25f6afae52decb8280285d2824d69c83.tar.gz | |
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 28 | ||||
| -rw-r--r-- | drivers/remoteproc/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/remoteproc/imx_rproc.c | 95 | ||||
| -rw-r--r-- | drivers/remoteproc/imx_rproc.h | 2 | ||||
| -rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 81 | ||||
| -rw-r--r-- | drivers/remoteproc/xlnx_r5_remoteproc.c | 100 |
6 files changed, 234 insertions, 73 deletions
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index b549d07f74971..155a7a9b37774 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -1452,6 +1452,34 @@ int zynqmp_pm_get_node_status(const u32 node, u32 *const status, EXPORT_SYMBOL_GPL(zynqmp_pm_get_node_status); /** + * zynqmp_pm_get_rpu_node_status - PM call to request a RPU node's current power state + * @node: ID of the RPU component or sub-system in question + * @status: Current operating state of the requested RPU node. + * @requirements: Current requirements asserted on the RPU node. + * @usage: Usage information, used for RPU slave nodes only: + * PM_USAGE_NO_MASTER - No master is currently using + * the node + * PM_USAGE_CURRENT_MASTER - Only requesting master is + * currently using the node + * PM_USAGE_OTHER_MASTER - Only other masters are + * currently using the node + * PM_USAGE_BOTH_MASTERS - Both the current and at least + * one other master is currently + * using the node + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_get_rpu_node_status(const u32 node, u32 *const status, + u32 *const requirements, u32 *const usage) +{ + if (zynqmp_pm_feature(PM_GET_NODE_STATUS) < PM_API_VERSION_2) + return -EOPNOTSUPP; + + return zynqmp_pm_get_node_status(node, status, requirements, usage); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_node_status); + +/** * zynqmp_pm_force_pwrdwn - PM call to request for another PU or subsystem to * be powered down forcefully * @node: Node ID of the targeted PU or subsystem diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index ee54436fea5ad..c78e431b7b2d8 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -316,7 +316,6 @@ config ST_SLIM_REMOTEPROC config STM32_RPROC tristate "STM32 remoteproc support" depends on ARCH_STM32 || COMPILE_TEST - depends on REMOTEPROC select MAILBOX help Say y here to support STM32 MCU processors via the diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 0dd80e688b0ea..7662ebd9d2f49 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -145,6 +145,41 @@ static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = { { 0x80000000, 0x80000000, 0x50000000, 0 }, }; +static const struct imx_rproc_att imx_rproc_att_imx94_m70[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x00000000, 0x203C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* TCM SYS NON-SECURE*/ + { 0x20000000, 0x20400000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, +}; + +static const struct imx_rproc_att imx_rproc_att_imx94_m71[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x00000000, 0x202C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* TCM SYS NON-SECURE*/ + { 0x20000000, 0x20300000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, +}; + +static const struct imx_rproc_att imx_rproc_att_imx94_m33s[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x0FFC0000, 0x209C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* TCM SYS NON-SECURE */ + { 0x20000000, 0x20A00000, 0x00040000, ATT_OWN | ATT_IOMEM }, + /* M33S OCRAM NON-SECURE */ + { 0x20800000, 0x20800000, 0x180000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, +}; + static const struct imx_rproc_att imx_rproc_att_imx93[] = { /* dev addr , sys addr , size , flags */ /* TCM CODE NON-SECURE */ @@ -339,13 +374,32 @@ static int imx_rproc_scu_api_start(struct rproc *rproc) return imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry); } +static u64 imx_rproc_sm_get_reset_vector(struct rproc *rproc) +{ + struct imx_rproc *priv = rproc->priv; + u32 reset_vector_mask = priv->dcfg->reset_vector_mask ?: GENMASK(31, 0); + + /* + * The hardware fetches the first two words from reset_vectors + * (hardware reset address) and populates SP and PC using the first + * two words. Execution proceeds from PC. The ELF entry point does + * not always match the hardware reset address. + * To derive the correct hardware reset address, the lower address + * bits must be masked off before programming the reset vector. + */ + return rproc->bootaddr & reset_vector_mask; +} + static int imx_rproc_sm_cpu_start(struct rproc *rproc) { struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; + u64 reset_vector; int ret; - ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false); + reset_vector = imx_rproc_sm_get_reset_vector(rproc); + + ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, reset_vector, true, false, false); if (ret) { dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret); return ret; @@ -359,13 +413,16 @@ static int imx_rproc_sm_lmm_start(struct rproc *rproc) struct imx_rproc *priv = rproc->priv; const struct imx_rproc_dcfg *dcfg = priv->dcfg; struct device *dev = priv->dev; + u64 reset_vector; int ret; + reset_vector = imx_rproc_sm_get_reset_vector(rproc); + /* * If the remoteproc core can't start the M7, it will already be * handled in imx_rproc_sm_lmm_prepare(). */ - ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0); + ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, reset_vector); if (ret) { dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n", dcfg->lmid, dcfg->cpuid, ret); @@ -1230,8 +1287,7 @@ static int imx_rproc_probe(struct platform_device *pdev) const struct imx_rproc_dcfg *dcfg; int ret; - /* set some other name then imx */ - rproc = devm_rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, + rproc = devm_rproc_alloc(dev, np->name, &imx_rproc_ops, NULL, sizeof(*priv)); if (!rproc) return -ENOMEM; @@ -1455,6 +1511,33 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { .flags = IMX_RPROC_NEED_CLKS, }; +static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m70 = { + .att = imx_rproc_att_imx94_m70, + .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m70), + .ops = &imx_rproc_ops_sm_lmm, + .cpuid = 1, + .lmid = 2, + .reset_vector_mask = GENMASK_U32(31, 16), +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m71 = { + .att = imx_rproc_att_imx94_m71, + .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m71), + .ops = &imx_rproc_ops_sm_lmm, + .cpuid = 7, + .lmid = 3, + .reset_vector_mask = GENMASK_U32(31, 16), +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx94_m33s = { + .att = imx_rproc_att_imx94_m33s, + .att_size = ARRAY_SIZE(imx_rproc_att_imx94_m33s), + .ops = &imx_rproc_ops_sm_lmm, + .cpuid = 8, + .lmid = 1, + .reset_vector_mask = GENMASK_U32(31, 16), +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { .att = imx_rproc_att_imx95_m7, .att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7), @@ -1462,6 +1545,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = { /* Must align with System Manager Firmware */ .cpuid = 1, /* Use 1 as cpu id for M7 core */ .lmid = 1, /* Use 1 as Logical Machine ID where M7 resides */ + .reset_vector_mask = GENMASK_U32(31, 16), }; static const struct of_device_id imx_rproc_of_match[] = { @@ -1478,6 +1562,9 @@ static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, { .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 }, + { .compatible = "fsl,imx94-cm70", .data = &imx_rproc_cfg_imx94_m70 }, + { .compatible = "fsl,imx94-cm71", .data = &imx_rproc_cfg_imx94_m71 }, + { .compatible = "fsl,imx94-cm33s", .data = &imx_rproc_cfg_imx94_m33s }, { .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 }, {}, }; diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index d37e6f90548ce..0d7d48352a109 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -41,6 +41,8 @@ struct imx_rproc_dcfg { /* For System Manager(SM) based SoCs */ u32 cpuid; /* ID of the remote core */ u32 lmid; /* ID of the Logcial Machine */ + /* reset_vector = elf_entry_addr & reset_vector_mask */ + u32 reset_vector_mask; }; #endif /* _IMX_RPROC_H */ diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index b087ed21858a8..f003be006b1bf 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -1011,60 +1011,55 @@ static rproc_handle_resource_t rproc_loading_handlers[RSC_LAST] = { [RSC_VDEV] = rproc_handle_vdev, }; -/* handle firmware resource entries before booting the remote processor */ -static int rproc_handle_resources(struct rproc *rproc, - rproc_handle_resource_t handlers[RSC_LAST]) +struct rproc_rsc_cb_data { + struct rproc *rproc; + rproc_handle_resource_t *handlers; +}; + +static int rproc_handle_rsc_entry(u32 type, void *rsc, int offset, + int avail, void *data) { + struct rproc_rsc_cb_data *d = data; + struct rproc *rproc = d->rproc; struct device *dev = &rproc->dev; rproc_handle_resource_t handler; - int ret = 0, i; - - if (!rproc->table_ptr) - return 0; + int ret; - for (i = 0; i < rproc->table_ptr->num; i++) { - int offset = rproc->table_ptr->offset[i]; - struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset; - int avail = rproc->table_sz - offset - sizeof(*hdr); - void *rsc = (void *)hdr + sizeof(*hdr); + dev_dbg(dev, "rsc: type %d\n", type); - /* make sure table isn't truncated */ - if (avail < 0) { - dev_err(dev, "rsc table is truncated\n"); - return -EINVAL; - } - - dev_dbg(dev, "rsc: type %d\n", hdr->type); + if (type >= RSC_VENDOR_START && type <= RSC_VENDOR_END) { + ret = rproc_handle_rsc(rproc, type, rsc, offset, avail); + if (ret == RSC_HANDLED) + return 0; + if (ret < 0) + return ret; + dev_warn(dev, "unsupported vendor resource %d\n", type); + return 0; + } - if (hdr->type >= RSC_VENDOR_START && - hdr->type <= RSC_VENDOR_END) { - ret = rproc_handle_rsc(rproc, hdr->type, rsc, - offset + sizeof(*hdr), avail); - if (ret == RSC_HANDLED) - continue; - else if (ret < 0) - break; + if (type >= RSC_LAST) { + dev_warn(dev, "unsupported resource %d\n", type); + return 0; + } - dev_warn(dev, "unsupported vendor resource %d\n", - hdr->type); - continue; - } + handler = d->handlers[type]; + if (!handler) + return 0; - if (hdr->type >= RSC_LAST) { - dev_warn(dev, "unsupported resource %d\n", hdr->type); - continue; - } + return handler(rproc, rsc, offset, avail); +} - handler = handlers[hdr->type]; - if (!handler) - continue; +/* handle firmware resource entries before booting the remote processor */ +static int rproc_handle_resources(struct rproc *rproc, + rproc_handle_resource_t handlers[RSC_LAST]) +{ + struct rproc_rsc_cb_data d = { .rproc = rproc, .handlers = handlers }; - ret = handler(rproc, rsc, offset + sizeof(*hdr), avail); - if (ret) - break; - } + if (!rproc->table_ptr) + return 0; - return ret; + return rsc_table_for_each_entry(rproc->table_ptr, rproc->table_sz, + &rproc->dev, rproc_handle_rsc_entry, &d); } static int rproc_prepare_subdevices(struct rproc *rproc) diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c index 50a9974f3202e..3349d18777510 100644 --- a/drivers/remoteproc/xlnx_r5_remoteproc.c +++ b/drivers/remoteproc/xlnx_r5_remoteproc.c @@ -4,7 +4,6 @@ * */ -#include <dt-bindings/power/xlnx-zynqmp-power.h> #include <linux/dma-mapping.h> #include <linux/firmware/xlnx-zynqmp.h> #include <linux/kernel.h> @@ -19,6 +18,11 @@ #include "remoteproc_internal.h" +#define PD_R5_0_ATCM 15 +#define PD_R5_0_BTCM 16 +#define PD_R5_1_ATCM 17 +#define PD_R5_1_BTCM 18 + /* IPI buffer MAX length */ #define IPI_BUF_LEN_MAX 32U @@ -899,17 +903,18 @@ static const struct rproc_ops zynqmp_r5_rproc_ops = { }; /** - * zynqmp_r5_add_rproc_core() - Add core data to framework. - * Allocate and add struct rproc object for each r5f core + * zynqmp_r5_alloc_rproc_core() - alloc rproc core data structure + * Allocate struct rproc object for each r5f core * This is called for each individual r5f core * * @cdev: Device node of each r5 core * * Return: zynqmp_r5_core object for success else error code pointer */ -static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) +static struct zynqmp_r5_core *zynqmp_r5_alloc_rproc_core(struct device *cdev) { struct zynqmp_r5_core *r5_core; + const char *fw_name = NULL; struct rproc *r5_rproc; int ret; @@ -918,10 +923,15 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) if (ret) return ERR_PTR(ret); + ret = rproc_of_parse_firmware(cdev, 0, &fw_name); + if (ret < 0 && ret != -EINVAL) + return ERR_PTR(dev_err_probe(cdev, ret, + "failed to parse firmware-name\n")); + /* Allocate remoteproc instance */ r5_rproc = rproc_alloc(cdev, dev_name(cdev), &zynqmp_r5_rproc_ops, - NULL, sizeof(struct zynqmp_r5_core)); + fw_name, sizeof(struct zynqmp_r5_core)); if (!r5_rproc) { dev_err(cdev, "failed to allocate memory for rproc instance\n"); return ERR_PTR(-ENOMEM); @@ -932,6 +942,11 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) r5_rproc->recovery_disabled = true; r5_rproc->has_iommu = false; r5_rproc->auto_boot = false; + + /* attempt to boot automatically if the firmware-name is provided */ + if (fw_name) + r5_rproc->auto_boot = true; + r5_core = r5_rproc->priv; r5_core->dev = cdev; r5_core->np = dev_of_node(cdev); @@ -941,23 +956,6 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) goto free_rproc; } - /* Add R5 remoteproc core */ - ret = rproc_add(r5_rproc); - if (ret) { - dev_err(cdev, "failed to add r5 remoteproc\n"); - goto free_rproc; - } - - /* - * If firmware is already available in the memory then move rproc state - * to DETACHED. Firmware can be preloaded via debugger or by any other - * agent (processors) in the system. - * If firmware isn't available in the memory and resource table isn't - * found, then rproc state remains OFFLINE. - */ - if (!zynqmp_r5_get_rsc_table_va(r5_core)) - r5_rproc->state = RPROC_DETACHED; - r5_core->rproc = r5_rproc; return r5_core; @@ -1210,6 +1208,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, { struct device *dev = cluster->dev; struct zynqmp_r5_core *r5_core; + u32 req, usage, status; int ret = -EINVAL, i; r5_core = cluster->r5_cores[0]; @@ -1255,6 +1254,42 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, ret = zynqmp_r5_get_sram_banks(r5_core); if (ret) return ret; + + /* + * It is possible that firmware is loaded into the memory, but + * RPU (remote) is not running. In such case, RPU state will be + * moved to RPROC_DETACHED wrongfully. To avoid it first make + * sure RPU is power-on and out of reset before parsing for the + * resource table. + */ + ret = zynqmp_pm_get_rpu_node_status(r5_core->pm_domain_id, + &status, &req, &usage); + if (ret) { + dev_warn(r5_core->dev, + "failed to get rpu node status, err %d\n", ret); + continue; + } + + /* + * If RPU state is power on and out of reset i.e. running, then + * assign RPROC_DETACHED state. If the RPU is not out of reset + * then do not attempt to attach to the remote processor. + */ + if (status == PM_NODE_RUNNING) { + /* + * Not all the firmware that is running on the remote + * core is expected to have the resource table. The + * firmware might not use RPMsg at all, and in that case + * resource table becomes irrelevant. However, we still + * need to make sure that running core is not reported + * as offline. so do not decide remote core state based + * on the resource table availability + */ + if (zynqmp_r5_get_rsc_table_va(r5_core)) + dev_dbg(r5_core->dev, "rsc tbl not found\n"); + r5_core->rproc->state = RPROC_DETACHED; + r5_core->rproc->auto_boot = true; + } } return 0; @@ -1278,7 +1313,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) enum rpu_oper_mode fw_reg_val; struct device **child_devs; enum rpu_tcm_comb tcm_mode; - int core_count, ret, i; + int core_count, ret, i, j; struct mbox_info *ipi; ret = of_property_read_u32(dev_node, "xlnx,cluster-mode", &cluster_mode); @@ -1364,7 +1399,7 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) child_devs[i] = &child_pdev->dev; /* create and add remoteproc instance of type struct rproc */ - r5_cores[i] = zynqmp_r5_add_rproc_core(&child_pdev->dev); + r5_cores[i] = zynqmp_r5_alloc_rproc_core(&child_pdev->dev); if (IS_ERR(r5_cores[i])) { ret = PTR_ERR(r5_cores[i]); r5_cores[i] = NULL; @@ -1409,16 +1444,31 @@ static int zynqmp_r5_cluster_init(struct zynqmp_r5_cluster *cluster) goto release_r5_cores; } + for (j = 0; j < cluster->core_count; j++) { + /* Add R5 remoteproc core */ + ret = rproc_add(r5_cores[j]->rproc); + if (ret) { + dev_err_probe(r5_cores[j]->dev, ret, + "failed to add remoteproc\n"); + goto delete_r5_cores; + } + } + kfree(child_devs); return 0; +delete_r5_cores: + i = core_count - 1; + /* delete previous added rproc */ + while (--j >= 0) + rproc_del(r5_cores[j]->rproc); + release_r5_cores: while (i >= 0) { put_device(child_devs[i]); if (r5_cores[i]) { zynqmp_r5_free_mbox(r5_cores[i]->ipi); of_reserved_mem_device_release(r5_cores[i]->dev); - rproc_del(r5_cores[i]->rproc); rproc_free(r5_cores[i]->rproc); } i--; |
