From c1407ac1099ab9726c31d38d806f3150f494c494 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 24 Jan 2022 13:09:13 +0100 Subject: [PATCH 01/22] remoteproc: mtk_scp: Use devm variant of rproc_alloc() To simplify the probe function, switch from using rproc_alloc() to devm_rproc_alloc(); while at it, also put everything on a single line, as it acceptably fits in 82 columns. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220124120915.41292-1-angelogioacchino.delregno@collabora.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 36e48cf58ed6..95a40e3f11e3 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -756,11 +756,7 @@ static int scp_probe(struct platform_device *pdev) char *fw_name = "scp.img"; int ret, i; - rproc = rproc_alloc(dev, - np->name, - &scp_ops, - fw_name, - sizeof(*scp)); + rproc = devm_rproc_alloc(dev, np->name, &scp_ops, fw_name, sizeof(*scp)); if (!rproc) { dev_err(dev, "unable to allocate remoteproc\n"); return -ENOMEM; @@ -776,8 +772,7 @@ static int scp_probe(struct platform_device *pdev) scp->sram_base = devm_ioremap_resource(dev, res); if (IS_ERR((__force void *)scp->sram_base)) { dev_err(dev, "Failed to parse and map sram memory\n"); - ret = PTR_ERR((__force void *)scp->sram_base); - goto free_rproc; + return PTR_ERR((__force void *)scp->sram_base); } scp->sram_size = resource_size(res); scp->sram_phys = res->start; @@ -789,7 +784,7 @@ static int scp_probe(struct platform_device *pdev) ret = PTR_ERR((__force void *)scp->l1tcm_base); if (ret != -EINVAL) { dev_err(dev, "Failed to map l1tcm memory\n"); - goto free_rproc; + return ret; } } else { scp->l1tcm_size = resource_size(res); @@ -851,8 +846,6 @@ destroy_mutex: for (i = 0; i < SCP_IPI_MAX; i++) mutex_destroy(&scp->ipi_desc[i].lock); mutex_destroy(&scp->send_lock); -free_rproc: - rproc_free(rproc); return ret; } From 77c792b91208b28ad5f09771f990a8d0278e7f29 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 24 Jan 2022 13:09:14 +0100 Subject: [PATCH 02/22] remoteproc: mtk_scp: Reorder scp_probe() sequence Cleanup the scp_probe() function by reordering some calls in this function, useful to reduce the usage of goto(s), and preparing for one more usage of dev_err_probe(). In particular, we can get the clocks before mapping the memory region, and move the mutexes initialization right before registering the ipi handler (which is the first mutex user in this driver). Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220124120915.41292-2-angelogioacchino.delregno@collabora.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 95a40e3f11e3..e40706b0e015 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -791,24 +791,23 @@ static int scp_probe(struct platform_device *pdev) scp->l1tcm_phys = res->start; } - mutex_init(&scp->send_lock); - for (i = 0; i < SCP_IPI_MAX; i++) - mutex_init(&scp->ipi_desc[i].lock); - scp->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); if (IS_ERR((__force void *)scp->reg_base)) { dev_err(dev, "Failed to parse and map cfg memory\n"); - ret = PTR_ERR((__force void *)scp->reg_base); - goto destroy_mutex; + return PTR_ERR((__force void *)scp->reg_base); } - ret = scp_map_memory_region(scp); - if (ret) - goto destroy_mutex; - ret = scp->data->scp_clk_get(scp); if (ret) - goto release_dev_mem; + return ret; + + ret = scp_map_memory_region(scp); + if (ret) + return ret; + + mutex_init(&scp->send_lock); + for (i = 0; i < SCP_IPI_MAX; i++) + mutex_init(&scp->ipi_desc[i].lock); /* register SCP initialization IPI */ ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp); @@ -842,7 +841,6 @@ remove_subdev: scp_ipi_unregister(scp, SCP_IPI_INIT); release_dev_mem: scp_unmap_memory_region(scp); -destroy_mutex: for (i = 0; i < SCP_IPI_MAX; i++) mutex_destroy(&scp->ipi_desc[i].lock); mutex_destroy(&scp->send_lock); From ae6062c4abdbf44c9cbae95805180e2fa1442b57 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 24 Jan 2022 13:09:15 +0100 Subject: [PATCH 03/22] remoteproc: mtk_scp: Use dev_err_probe() where possible Simplify the probe function, where possible, by using dev_err_probe(). While at it, as to increase human readability, also remove some unnecessary forced void pointer casts that were previously used in error checking. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220124120915.41292-3-angelogioacchino.delregno@collabora.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/mtk_scp.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index e40706b0e015..dcddb33e9997 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -757,10 +757,8 @@ static int scp_probe(struct platform_device *pdev) int ret, i; rproc = devm_rproc_alloc(dev, np->name, &scp_ops, fw_name, sizeof(*scp)); - if (!rproc) { - dev_err(dev, "unable to allocate remoteproc\n"); - return -ENOMEM; - } + if (!rproc) + return dev_err_probe(dev, -ENOMEM, "unable to allocate remoteproc\n"); scp = (struct mtk_scp *)rproc->priv; scp->rproc = rproc; @@ -770,21 +768,20 @@ static int scp_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); scp->sram_base = devm_ioremap_resource(dev, res); - if (IS_ERR((__force void *)scp->sram_base)) { - dev_err(dev, "Failed to parse and map sram memory\n"); - return PTR_ERR((__force void *)scp->sram_base); - } + if (IS_ERR(scp->sram_base)) + return dev_err_probe(dev, PTR_ERR(scp->sram_base), + "Failed to parse and map sram memory\n"); + scp->sram_size = resource_size(res); scp->sram_phys = res->start; /* l1tcm is an optional memory region */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "l1tcm"); scp->l1tcm_base = devm_ioremap_resource(dev, res); - if (IS_ERR((__force void *)scp->l1tcm_base)) { - ret = PTR_ERR((__force void *)scp->l1tcm_base); + if (IS_ERR(scp->l1tcm_base)) { + ret = PTR_ERR(scp->l1tcm_base); if (ret != -EINVAL) { - dev_err(dev, "Failed to map l1tcm memory\n"); - return ret; + return dev_err_probe(dev, ret, "Failed to map l1tcm memory\n"); } } else { scp->l1tcm_size = resource_size(res); @@ -792,10 +789,9 @@ static int scp_probe(struct platform_device *pdev) } scp->reg_base = devm_platform_ioremap_resource_byname(pdev, "cfg"); - if (IS_ERR((__force void *)scp->reg_base)) { - dev_err(dev, "Failed to parse and map cfg memory\n"); - return PTR_ERR((__force void *)scp->reg_base); - } + if (IS_ERR(scp->reg_base)) + return dev_err_probe(dev, PTR_ERR(scp->reg_base), + "Failed to parse and map cfg memory\n"); ret = scp->data->scp_clk_get(scp); if (ret) From f89672cc3681952f2d06314981a6b45f8b0045d1 Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Wed, 19 Jan 2022 23:21:39 +0000 Subject: [PATCH 04/22] remoteproc: Fix count check in rproc_coredump_write() Check count for 0, to avoid a potential underflow. Make the check the same as the one in rproc_recovery_write(). Fixes: 3afdc59e4390 ("remoteproc: Add coredump debugfs entry") Signed-off-by: Alistair Delva Cc: Rishabh Bhatnagar Cc: stable@vger.kernel.org Cc: Ohad Ben-Cohen Cc: Bjorn Andersson Cc: Mathieu Poirier Cc: Sibi Sankar Cc: linux-remoteproc@vger.kernel.org Cc: kernel-team@android.com Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220119232139.1125908-1-adelva@google.com --- drivers/remoteproc/remoteproc_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index b5a1e3b697d9..581930483ef8 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -76,7 +76,7 @@ static ssize_t rproc_coredump_write(struct file *filp, int ret, err = 0; char buf[20]; - if (count > sizeof(buf)) + if (count < 1 || count > sizeof(buf)) return -EINVAL; ret = copy_from_user(buf, user_buf, count); From 26c9da51949916b73d995a2c89412c346903273d Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Wed, 16 Feb 2022 13:42:23 +0530 Subject: [PATCH 05/22] remoteproc: Introduce sysfs_read_only flag The remoteproc framework provides sysfs interfaces for changing the firmware name and for starting/stopping a remote processor through the sysfs files 'state' and 'firmware'. The 'coredump' file is used to set the coredump configuration. The 'recovery' sysfs file can also be used similarly to control the error recovery state machine of a remoteproc. These interfaces are currently allowed irrespective of how the remoteprocs were booted (like remoteproc self auto-boot, remoteproc client-driven boot etc). These interfaces can adversely affect a remoteproc and its clients especially when a remoteproc is being controlled by a remoteproc client driver(s). Also, not all remoteproc drivers may want to support the sysfs interfaces by default. Add support to make the remoteproc sysfs files read only by introducing a state flag 'sysfs_read_only' that the individual remoteproc drivers can set based on their usage needs. The default behavior is to allow the sysfs operations as before. Implement attribute_group->is_visible() to make the sysfs entries read only when 'sysfs_read_only' flag is set. Signed-off-by: Puranjay Mohan Link: https://lore.kernel.org/r/20220216081224.9956-2-p-mohan@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/remoteproc_sysfs.c | 19 ++++++++++++++++++- include/linux/remoteproc.h | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index ea8b89f97d7b..abf0cd05d5e1 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -230,6 +230,22 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(name); +static umode_t rproc_is_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct rproc *rproc = to_rproc(dev); + umode_t mode = attr->mode; + + if (rproc->sysfs_read_only && (attr == &dev_attr_recovery.attr || + attr == &dev_attr_firmware.attr || + attr == &dev_attr_state.attr || + attr == &dev_attr_coredump.attr)) + mode = 0444; + + return mode; +} + static struct attribute *rproc_attrs[] = { &dev_attr_coredump.attr, &dev_attr_recovery.attr, @@ -240,7 +256,8 @@ static struct attribute *rproc_attrs[] = { }; static const struct attribute_group rproc_devgroup = { - .attrs = rproc_attrs + .attrs = rproc_attrs, + .is_visible = rproc_is_visible, }; static const struct attribute_group *rproc_devgroups[] = { diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index e0600e1e5c17..93a1d0050fbc 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -523,6 +523,7 @@ struct rproc_dump_segment { * @table_sz: size of @cached_table * @has_iommu: flag to indicate if remote processor is behind an MMU * @auto_boot: flag to indicate if remote processor should be auto-started + * @sysfs_read_only: flag to make remoteproc sysfs files read only * @dump_segments: list of segments in the firmware * @nb_vdev: number of vdev currently handled by rproc * @elf_class: firmware ELF class @@ -562,6 +563,7 @@ struct rproc { size_t table_sz; bool has_iommu; bool auto_boot; + bool sysfs_read_only; struct list_head dump_segments; int nb_vdev; u8 elf_class; From 19e7bf836997f37b7c70cf8f3091e76b79769673 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 16 Feb 2022 13:42:24 +0530 Subject: [PATCH 06/22] remoteproc: wkup_m3: Set sysfs_read_only flag The Wakeup M3 remote processor is controlled by the wkup_m3_ipc client driver, so set the newly introduced 'sysfs_read_only' flag to not allow any overriding of the remoteproc firmware, state, recovery, or coredump from userspace. Signed-off-by: Suman Anna Signed-off-by: Puranjay Mohan Link: https://lore.kernel.org/r/20220216081224.9956-3-p-mohan@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/wkup_m3_rproc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 484f7605823e..a0c204cb0979 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -163,6 +163,7 @@ static int wkup_m3_rproc_probe(struct platform_device *pdev) } rproc->auto_boot = false; + rproc->sysfs_read_only = true; wkupm3 = rproc->priv; wkupm3->rproc = rproc; From b65700d046a60d0a29f6289e13c62d0c93689f11 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 8 Mar 2022 18:25:15 +0100 Subject: [PATCH 07/22] remoteproc: move rproc_da_to_va declaration to remoteproc.h The rproc_da_to_va() API is an exported function, so move its declaration from the remoteproc local remoteproc_internal.h to the public remoteproc.h file. This will allow drivers outside of the remoteproc folder to be able to use this API. Signed-off-by: Suman Anna Signed-off-by: Dave Gerlach [adjusted line numbers to apply] Signed-off-by: Drew Fustini Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220308172515.29556-1-dfustini@baylibre.com --- drivers/remoteproc/remoteproc_internal.h | 1 - include/linux/remoteproc.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index a328e634b1de..72d4d3d7d94d 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -84,7 +84,6 @@ static inline void rproc_char_device_remove(struct rproc *rproc) void rproc_free_vring(struct rproc_vring *rvring); int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); -void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem); phys_addr_t rproc_va_to_pa(void *cpu_addr); int rproc_trigger_recovery(struct rproc *rproc); diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 93a1d0050fbc..b2ee325e0af1 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -675,6 +675,7 @@ void rproc_shutdown(struct rproc *rproc); int rproc_detach(struct rproc *rproc); int rproc_set_firmware(struct rproc *rproc, const char *fw_name); void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem); void rproc_coredump_using_sections(struct rproc *rproc); int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size); int rproc_coredump_add_custom_segment(struct rproc *rproc, From 505b5b1616e200042999de715dbe7c1e2735cd65 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 8 Mar 2022 03:12:19 +0000 Subject: [PATCH 08/22] remoteproc: qcom: Fix missing of_node_put in adsp_alloc_memory_region The device_node pointer is returned by of_parse_phandle() with refcount incremented. We should use of_node_put() on it when done. Fixes: dc160e449122 ("remoteproc: qcom: Introduce Non-PAS ADSP PIL driver") Signed-off-by: Miaoqian Lin Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220308031219.4718-1-linmq006@gmail.com --- drivers/remoteproc/qcom_q6v5_adsp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 098362e6e233..7c02bc132247 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -408,6 +408,7 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) } ret = of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) return ret; From 8f90161a66bc3d6b9fe8dde4d9028d20eae1b62a Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 8 Mar 2022 06:31:02 +0000 Subject: [PATCH 09/22] remoteproc: qcom_wcnss: Add missing of_node_put() in wcnss_alloc_memory_region The device_node pointer is returned by of_parse_phandle() with refcount incremented. We should use of_node_put() on it when done. Fixes: aed361adca9f ("remoteproc: qcom: Introduce WCNSS peripheral image loader") Signed-off-by: Miaoqian Lin Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220308063102.10049-1-linmq006@gmail.com --- drivers/remoteproc/qcom_wcnss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 80bbafee9846..9a223d394087 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -500,6 +500,7 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss) } ret = of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) return ret; From 07a5dcc4bed9d7cae54adf5aa10ff9f037a3204b Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 8 Mar 2022 06:45:21 +0000 Subject: [PATCH 10/22] remoteproc: qcom_q6v5_mss: Fix some leaks in q6v5_alloc_memory_region The device_node pointer is returned by of_parse_phandle() or of_get_child_by_name() with refcount incremented. We should use of_node_put() on it when done. This function only call of_node_put(node) when of_address_to_resource succeeds, missing error cases. Fixes: 278d744c46fd ("remoteproc: qcom: Fix potential device node leaks") Fixes: 051fb70fd4ea ("remoteproc: qcom: Driver for the self-authenticating Hexagon v5") Signed-off-by: Miaoqian Lin Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220308064522.13804-1-linmq006@gmail.com --- drivers/remoteproc/qcom_q6v5_mss.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 43ea8455546c..b9ab91540b00 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -1806,18 +1806,20 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) * reserved memory regions from device's memory-region property. */ child = of_get_child_by_name(qproc->dev->of_node, "mba"); - if (!child) + if (!child) { node = of_parse_phandle(qproc->dev->of_node, "memory-region", 0); - else + } else { node = of_parse_phandle(child, "memory-region", 0); + of_node_put(child); + } ret = of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mba region\n"); return ret; } - of_node_put(node); qproc->mba_phys = r.start; qproc->mba_size = resource_size(&r); @@ -1828,14 +1830,15 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) } else { child = of_get_child_by_name(qproc->dev->of_node, "mpss"); node = of_parse_phandle(child, "memory-region", 0); + of_node_put(child); } ret = of_address_to_resource(node, 0, &r); + of_node_put(node); if (ret) { dev_err(qproc->dev, "unable to resolve mpss region\n"); return ret; } - of_node_put(node); qproc->mpss_phys = qproc->mpss_reloc = r.start; qproc->mpss_size = resource_size(&r); From 22335385157d6eedb659a4cd0c801d62bfe0881d Mon Sep 17 00:00:00 2001 From: Allen-KH Cheng Date: Fri, 25 Feb 2022 21:27:46 +0800 Subject: [PATCH 11/22] dt-bindings: remoteproc: mediatek: Add binding for mt8186 scp Add mt8186 compatible to binding document. Signed-off-by: Allen-KH Cheng Reviewed-by: AngeloGioacchino Del Regno Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220225132747.31808-2-allen-kh.cheng@mediatek.com --- Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml index d21a25ee96e6..5b693a2d049c 100644 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - mediatek,mt8183-scp + - mediatek,mt8186-scp - mediatek,mt8192-scp - mediatek,mt8195-scp From 80d691854ffbf99c8a88584703e0141b31e63205 Mon Sep 17 00:00:00 2001 From: Allen-KH Cheng Date: Fri, 25 Feb 2022 21:27:47 +0800 Subject: [PATCH 12/22] remoteproc: mediatek: Support mt8186 scp Add SCP support for mt8186 Signed-off-by: Allen-KH Cheng Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220225132747.31808-3-allen-kh.cheng@mediatek.com --- drivers/remoteproc/mtk_common.h | 3 +++ drivers/remoteproc/mtk_scp.c | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index 5ff3867c72f3..71ce4977cb0b 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -32,6 +32,9 @@ #define MT8183_SCP_CACHESIZE_8KB BIT(8) #define MT8183_SCP_CACHE_CON_WAYEN BIT(10) +#define MT8186_SCP_L1_SRAM_PD_P1 0x40B0 +#define MT8186_SCP_L1_SRAM_PD_p2 0x40B4 + #define MT8192_L2TCM_SRAM_PD_0 0x10C0 #define MT8192_L2TCM_SRAM_PD_1 0x10C4 #define MT8192_L2TCM_SRAM_PD_2 0x10C8 diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index dcddb33e9997..38609153bf64 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -383,6 +383,27 @@ static void mt8192_power_off_sram(void __iomem *addr) writel(GENMASK(i, 0), addr); } +static int mt8186_scp_before_load(struct mtk_scp *scp) +{ + /* Clear SCP to host interrupt */ + writel(MT8183_SCP_IPC_INT_BIT, scp->reg_base + MT8183_SCP_TO_HOST); + + /* Reset clocks before loading FW */ + writel(0x0, scp->reg_base + MT8183_SCP_CLK_SW_SEL); + writel(0x0, scp->reg_base + MT8183_SCP_CLK_DIV_SEL); + + /* Turn on the power of SCP's SRAM before using it. Enable 1 block per time*/ + mt8192_power_on_sram(scp->reg_base + MT8183_SCP_SRAM_PDN); + + /* Initialize TCM before loading FW. */ + writel(0x0, scp->reg_base + MT8183_SCP_L1_SRAM_PD); + writel(0x0, scp->reg_base + MT8183_SCP_TCM_TAIL_SRAM_PD); + writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_P1); + writel(0x0, scp->reg_base + MT8186_SCP_L1_SRAM_PD_p2); + + return 0; +} + static int mt8192_scp_before_load(struct mtk_scp *scp) { /* clear SPM interrupt, SCP2SPM_IPC_CLR */ @@ -874,6 +895,19 @@ static const struct mtk_scp_of_data mt8183_of_data = { .ipi_buf_offset = 0x7bdb0, }; +static const struct mtk_scp_of_data mt8186_of_data = { + .scp_clk_get = mt8195_scp_clk_get, + .scp_before_load = mt8186_scp_before_load, + .scp_irq_handler = mt8183_scp_irq_handler, + .scp_reset_assert = mt8183_scp_reset_assert, + .scp_reset_deassert = mt8183_scp_reset_deassert, + .scp_stop = mt8183_scp_stop, + .scp_da_to_va = mt8183_scp_da_to_va, + .host_to_scp_reg = MT8183_HOST_TO_SCP, + .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT, + .ipi_buf_offset = 0x7bdb0, +}; + static const struct mtk_scp_of_data mt8192_of_data = { .scp_clk_get = mt8192_scp_clk_get, .scp_before_load = mt8192_scp_before_load, @@ -900,6 +934,7 @@ static const struct mtk_scp_of_data mt8195_of_data = { static const struct of_device_id mtk_scp_of_match[] = { { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, + { .compatible = "mediatek,mt8186-scp", .data = &mt8186_of_data }, { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, { .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data }, {}, From 8d9be5c6bdcda9e29597d3fbb24d1f6699da4616 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 24 Feb 2022 19:32:24 -0800 Subject: [PATCH 13/22] remoteproc: qcom: q6v5: Add interconnect path proxy vote Many remoteproc instances requires that Linux casts a proxy vote for an interconnect path during boot, until they can do it themselves. Add support for voting for a single path. As this is a shared problem between both PAS and MSS drivers, the path is acquired and votes casted from the common helper code. Signed-off-by: Bjorn Andersson Reviewed-by: Georgi Djakov Link: https://lore.kernel.org/r/20220225033224.2238425-1-bjorn.andersson@linaro.org --- drivers/remoteproc/qcom_q6v5.c | 23 +++++++++++++++++++++-- drivers/remoteproc/qcom_q6v5.h | 3 +++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 442a388f8102..5280ec9b5449 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -51,9 +52,17 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5) { int ret; - ret = q6v5_load_state_toggle(q6v5, true); - if (ret) + ret = icc_set_bw(q6v5->path, 0, UINT_MAX); + if (ret < 0) { + dev_err(q6v5->dev, "failed to set bandwidth request\n"); return ret; + } + + ret = q6v5_load_state_toggle(q6v5, true); + if (ret) { + icc_set_bw(q6v5->path, 0, 0); + return ret; + } reinit_completion(&q6v5->start_done); reinit_completion(&q6v5->stop_done); @@ -78,6 +87,9 @@ int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5) disable_irq(q6v5->handover_irq); q6v5_load_state_toggle(q6v5, false); + /* Disable interconnect vote, in case handover never happened */ + icc_set_bw(q6v5->path, 0, 0); + return !q6v5->handover_issued; } EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare); @@ -160,6 +172,8 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data) if (q6v5->handover) q6v5->handover(q6v5); + icc_set_bw(q6v5->path, 0, 0); + q6v5->handover_issued = true; return IRQ_HANDLED; @@ -332,6 +346,11 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, return load_state ? -ENOMEM : -EINVAL; } + q6v5->path = devm_of_icc_get(&pdev->dev, NULL); + if (IS_ERR(q6v5->path)) + return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->path), + "failed to acquire interconnect path\n"); + return 0; } EXPORT_SYMBOL_GPL(qcom_q6v5_init); diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h index f35e04471ed7..5a859c41896e 100644 --- a/drivers/remoteproc/qcom_q6v5.h +++ b/drivers/remoteproc/qcom_q6v5.h @@ -7,6 +7,7 @@ #include #include +struct icc_path; struct rproc; struct qcom_smem_state; struct qcom_sysmon; @@ -18,6 +19,8 @@ struct qcom_q6v5 { struct qcom_smem_state *state; struct qmp *qmp; + struct icc_path *path; + unsigned stop_bit; int wdog_irq; From c13b780c4597e1e6cee3154053a196aa329b1367 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Sun, 13 Feb 2022 14:12:42 -0600 Subject: [PATCH 14/22] remoteproc: Change rproc_shutdown() to return a status The rproc_shutdown() function is currently not returning any error code, and any failures within rproc_stop() are not passed back to the users. Change the signature to return a success value back to the callers. The remoteproc sysfs and cdev interfaces are also updated to return back this status to userspace. Signed-off-by: Suman Anna Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220213201246.25952-2-s-anna@ti.com --- Documentation/staging/remoteproc.rst | 3 ++- drivers/remoteproc/remoteproc_cdev.c | 2 +- drivers/remoteproc/remoteproc_core.c | 9 ++++++--- drivers/remoteproc/remoteproc_sysfs.c | 2 +- include/linux/remoteproc.h | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Documentation/staging/remoteproc.rst b/Documentation/staging/remoteproc.rst index 9cccd3dd6a4b..348ee7e508ac 100644 --- a/Documentation/staging/remoteproc.rst +++ b/Documentation/staging/remoteproc.rst @@ -49,13 +49,14 @@ might also consider using dev_archdata for this). :: - void rproc_shutdown(struct rproc *rproc) + int rproc_shutdown(struct rproc *rproc) Power off a remote processor (previously booted with rproc_boot()). In case @rproc is still being used by an additional user(s), then this function will just decrement the power refcount and exit, without really powering off the device. +Returns 0 on success, and an appropriate error value otherwise. Every call to rproc_boot() must (eventually) be accompanied by a call to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug. diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c index 4ad98b0b8caa..906ff3c4dfdd 100644 --- a/drivers/remoteproc/remoteproc_cdev.c +++ b/drivers/remoteproc/remoteproc_cdev.c @@ -42,7 +42,7 @@ static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_ rproc->state != RPROC_ATTACHED) return -EINVAL; - rproc_shutdown(rproc); + ret = rproc_shutdown(rproc); } else if (!strncmp(cmd, "detach", len)) { if (rproc->state != RPROC_ATTACHED) return -EINVAL; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 69f51acf235e..c510125769b9 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -2061,16 +2061,18 @@ EXPORT_SYMBOL(rproc_boot); * which means that the @rproc handle stays valid even after rproc_shutdown() * returns, and users can still use it with a subsequent rproc_boot(), if * needed. + * + * Return: 0 on success, and an appropriate error value otherwise */ -void rproc_shutdown(struct rproc *rproc) +int rproc_shutdown(struct rproc *rproc) { struct device *dev = &rproc->dev; - int ret; + int ret = 0; ret = mutex_lock_interruptible(&rproc->lock); if (ret) { dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret); - return; + return ret; } /* if the remote proc is still needed, bail out */ @@ -2097,6 +2099,7 @@ void rproc_shutdown(struct rproc *rproc) rproc->table_ptr = NULL; out: mutex_unlock(&rproc->lock); + return ret; } EXPORT_SYMBOL(rproc_shutdown); diff --git a/drivers/remoteproc/remoteproc_sysfs.c b/drivers/remoteproc/remoteproc_sysfs.c index abf0cd05d5e1..51a04bc6ba7a 100644 --- a/drivers/remoteproc/remoteproc_sysfs.c +++ b/drivers/remoteproc/remoteproc_sysfs.c @@ -206,7 +206,7 @@ static ssize_t state_store(struct device *dev, rproc->state != RPROC_ATTACHED) return -EINVAL; - rproc_shutdown(rproc); + ret = rproc_shutdown(rproc); } else if (sysfs_streq(buf, "detach")) { if (rproc->state != RPROC_ATTACHED) return -EINVAL; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index b2ee325e0af1..7c943f0a2fc4 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -671,7 +671,7 @@ rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len, u32 da, const char *name, ...); int rproc_boot(struct rproc *rproc); -void rproc_shutdown(struct rproc *rproc); +int rproc_shutdown(struct rproc *rproc); int rproc_detach(struct rproc *rproc); int rproc_set_firmware(struct rproc *rproc, const char *fw_name); void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); From e3865c85385aa0c882702039a66f8e1c973bd55c Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Sun, 13 Feb 2022 14:12:43 -0600 Subject: [PATCH 15/22] remoteproc: k3-r5: Refactor mbox request code in start Refactor out the mailbox request and associated ping logic code from k3_r5_rproc_start() function into its own separate function so that it can be re-used in the soon to be added .attach() ops callback. Signed-off-by: Suman Anna Reviewed-by: Mathieu Poirier Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220213201246.25952-3-s-anna@ti.com --- drivers/remoteproc/ti_k3_r5_remoteproc.c | 68 ++++++++++++++---------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 969531c05b13..ff4e1fac1c7f 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -2,7 +2,7 @@ /* * TI K3 R5F (MCU) Remote Processor driver * - * Copyright (C) 2017-2020 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2017-2022 Texas Instruments Incorporated - https://www.ti.com/ * Suman Anna */ @@ -376,6 +376,44 @@ static inline int k3_r5_core_run(struct k3_r5_core *core) 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)) { + ret = -EBUSY; + dev_err(dev, "mbox_request_channel failed: %ld\n", + PTR_ERR(kproc->mbox)); + return 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); + 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 @@ -495,38 +533,14 @@ static int k3_r5_rproc_start(struct rproc *rproc) { struct k3_r5_rproc *kproc = rproc->priv; struct k3_r5_cluster *cluster = kproc->cluster; - struct mbox_client *client = &kproc->client; struct device *dev = kproc->dev; struct k3_r5_core *core; u32 boot_addr; 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)) { - ret = -EBUSY; - dev_err(dev, "mbox_request_channel failed: %ld\n", - PTR_ERR(kproc->mbox)); + ret = k3_r5_rproc_request_mbox(rproc); + if (ret) return 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); - goto put_mbox; - } boot_addr = rproc->bootaddr; /* TODO: add boot_addr sanity checking */ From 1168af40b1ad8cb2e78f4a70869fa4a076320e4f Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Sun, 13 Feb 2022 14:12:44 -0600 Subject: [PATCH 16/22] remoteproc: k3-r5: Add support for IPC-only mode for all R5Fs Add support to the K3 R5F remoteproc driver to configure all the R5F cores to be either in IPC-only mode or the traditional remoteproc mode. The IPC-only mode expects that the remote processors are already booted by the bootloader, and only performs the minimum steps required to initialize and deinitialize the virtio IPC transports. The remoteproc mode allows the kernel remoteproc driver to do the regular load and boot and other device management operations for a R5F core. The IPC-only mode for a R5F core is detected and configured at driver probe time by querying the System Firmware for the R5F power and reset state and/or status and making sure that the R5F core is indeed started by the bootloaders, otherwise the device is configured for remoteproc mode. Support for IPC-only mode is achieved through .attach(), .detach() and .get_loaded_rsc_table() callback ops and zeroing out the regular rproc ops .prepare(), .unprepare(), .start() and .stop(). The resource table follows a design-by-contract approach and is expected to be at the base of the DDR firmware region reserved for each remoteproc, it is mostly expected to contain only the virtio device and trace resource entries. NOTE: The driver cannot configure a R5F core for remoteproc mode by any means without rebooting the kernel if that R5F core has been started by a bootloader. This is the current desired behavior and can be enhanced in the future if the feature is needed. Signed-off-by: Suman Anna Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220213201246.25952-4-s-anna@ti.com --- drivers/remoteproc/ti_k3_r5_remoteproc.c | 219 ++++++++++++++++++++++- 1 file changed, 215 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index ff4e1fac1c7f..4840ad906018 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -428,6 +428,7 @@ static int k3_r5_rproc_request_mbox(struct rproc *rproc) * private to each core. Only Core0 needs to be unhalted for running the * cluster in this mode. The function uses the same reset logic as LockStep * mode for this (though the behavior is agnostic of the reset release order). + * This callback is invoked only in remoteproc mode. */ static int k3_r5_rproc_prepare(struct rproc *rproc) { @@ -493,7 +494,8 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) * both cores. The access is made possible only with releasing the resets for * both cores, but with only Core0 unhalted. This function re-uses the same * reset assert logic as LockStep mode for this mode (though the behavior is - * agnostic of the reset assert order). + * agnostic of the reset assert order). This callback is invoked only in + * remoteproc mode. */ static int k3_r5_rproc_unprepare(struct rproc *rproc) { @@ -527,7 +529,8 @@ static int k3_r5_rproc_unprepare(struct rproc *rproc) * * The Single-CPU mode on applicable SoCs (eg: AM64x) only uses Core0 to execute * code, so only Core0 needs to be unhalted. The function uses the same logic - * flow as Split-mode for this. + * flow as Split-mode for this. This callback is invoked only in remoteproc + * mode. */ static int k3_r5_rproc_start(struct rproc *rproc) { @@ -598,7 +601,8 @@ put_mbox: * be done here, but is preferred to be done in the .unprepare() ops - this * maintains the symmetric behavior between the .start(), .stop(), .prepare() * and .unprepare() ops, and also balances them well between sysfs 'state' - * flow and device bind/unbind or module removal. + * flow and device bind/unbind or module removal. This callback is invoked + * only in remoteproc mode. */ static int k3_r5_rproc_stop(struct rproc *rproc) { @@ -635,6 +639,78 @@ out: return ret; } +/* + * Attach to a running R5F remote processor (IPC-only mode) + * + * The R5F attach callback only needs to request the mailbox, the remote + * processor is already booted, 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. + */ +static int k3_r5_rproc_attach(struct rproc *rproc) +{ + struct k3_r5_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + ret = k3_r5_rproc_request_mbox(rproc); + if (ret) + return ret; + + dev_info(dev, "R5F core initialized in IPC-only mode\n"); + return 0; +} + +/* + * Detach from a running R5F remote processor (IPC-only mode) + * + * The R5F detach callback performs the opposite operation to attach callback + * and only needs to release the mailbox, 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. + */ +static int k3_r5_rproc_detach(struct rproc *rproc) +{ + struct k3_r5_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + + mbox_free_channel(kproc->mbox); + dev_info(dev, "R5F core deinitialized in IPC-only mode\n"); + 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 * @@ -1014,6 +1090,116 @@ static void k3_r5_adjust_tcm_sizes(struct k3_r5_rproc *kproc) } } +/* + * This function checks and configures a R5F core for IPC-only or remoteproc + * mode. The driver is configured to be in IPC-only mode for a R5F core when + * the core has been loaded and started by a bootloader. The IPC-only mode is + * detected by querying the System Firmware for reset, power on and halt status + * and ensuring that the core is running. Any incomplete steps at bootloader + * are validated and errored out. + * + * In IPC-only mode, the driver state flags for ATCM, BTCM and LOCZRAMA settings + * and cluster mode parsed originally from kernel DT are updated to reflect the + * 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) +{ + struct k3_r5_cluster *cluster = kproc->cluster; + struct k3_r5_core *core = kproc->core; + struct device *cdev = core->dev; + bool r_state = false, c_state = 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; + 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); + if (ret) { + dev_err(cdev, "failed to get initial state, mode cannot be determined, ret = %d\n", + ret); + return ret; + } + if (r_state != c_state) { + dev_warn(cdev, "R5F core may have been powered on by a different host, programmed state (%d) != actual state (%d)\n", + r_state, c_state); + } + + ret = reset_control_status(core->reset); + if (ret < 0) { + dev_err(cdev, "failed to get initial local reset status, ret = %d\n", + ret); + return ret; + } + + ret = ti_sci_proc_get_status(core->tsp, &boot_vec, &cfg, &ctrl, + &stat); + if (ret < 0) { + dev_err(cdev, "failed to get initial processor status, ret = %d\n", + ret); + return ret; + } + atcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_ATCM_EN ? 1 : 0; + btcm_enable = cfg & PROC_BOOT_CFG_FLAG_R5_BTCM_EN ? 1 : 0; + loczrama = cfg & PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE ? 1 : 0; + if (cluster->soc_data->single_cpu_mode) { + mode = cfg & PROC_BOOT_CFG_FLAG_R5_SINGLE_CORE ? + CLUSTER_MODE_SINGLECPU : CLUSTER_MODE_SPLIT; + } else { + mode = cfg & PROC_BOOT_CFG_FLAG_R5_LOCKSTEP ? + CLUSTER_MODE_LOCKSTEP : CLUSTER_MODE_SPLIT; + } + halted = ctrl & PROC_BOOT_CTRL_FLAG_R5_CORE_HALT; + + /* + * IPC-only mode detection requires both local and module resets to + * be deasserted and R5F core to be unhalted. Local reset status is + * irrelevant if module reset is asserted (POR value has local reset + * deasserted), and is deemed as remoteproc mode + */ + if (c_state && !ret && !halted) { + dev_info(cdev, "configured R5F for IPC-only mode\n"); + kproc->rproc->state = RPROC_DETACHED; + ret = 1; + /* override rproc ops with only required IPC-only mode ops */ + kproc->rproc->ops->prepare = NULL; + 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->get_loaded_rsc_table = + k3_r5_get_loaded_rsc_table; + } else if (!c_state) { + dev_info(cdev, "configured R5F for remoteproc mode\n"); + ret = 0; + } else { + dev_err(cdev, "mismatched mode: local_reset = %s, module_reset = %s, core_state = %s\n", + !ret ? "deasserted" : "asserted", + c_state ? "deasserted" : "asserted", + halted ? "halted" : "unhalted"); + ret = -EINVAL; + } + + /* fixup TCMs, cluster & core flags to actual values in IPC-only mode */ + if (ret > 0) { + if (core == core0) + cluster->mode = mode; + 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; + } + + return ret; +} + static int k3_r5_cluster_rproc_init(struct platform_device *pdev) { struct k3_r5_cluster *cluster = platform_get_drvdata(pdev); @@ -1023,7 +1209,7 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) struct device *cdev; const char *fw_name; struct rproc *rproc; - int ret; + int ret, ret1; core1 = list_last_entry(&cluster->cores, struct k3_r5_core, elem); list_for_each_entry(core, &cluster->cores, elem) { @@ -1054,6 +1240,12 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) kproc->rproc = rproc; core->rproc = rproc; + ret = k3_r5_rproc_configure_mode(kproc); + if (ret < 0) + goto err_config; + if (ret) + goto init_rmem; + ret = k3_r5_rproc_configure(kproc); if (ret) { dev_err(dev, "initial configure failed, ret = %d\n", @@ -1061,6 +1253,7 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) goto err_config; } +init_rmem: k3_r5_adjust_tcm_sizes(kproc); ret = k3_r5_reserved_mem_init(kproc); @@ -1085,6 +1278,15 @@ static int k3_r5_cluster_rproc_init(struct platform_device *pdev) return 0; err_split: + if (rproc->state == RPROC_ATTACHED) { + ret1 = rproc_detach(rproc); + if (ret1) { + dev_err(kproc->dev, "failed to detach rproc, ret = %d\n", + ret1); + return ret1; + } + } + rproc_del(rproc); err_add: k3_r5_reserved_mem_exit(kproc); @@ -1108,6 +1310,7 @@ static void k3_r5_cluster_rproc_exit(void *data) struct k3_r5_rproc *kproc; struct k3_r5_core *core; struct rproc *rproc; + int ret; /* * lockstep mode and single-cpu modes have only one rproc associated @@ -1123,6 +1326,14 @@ static void k3_r5_cluster_rproc_exit(void *data) rproc = core->rproc; kproc = rproc->priv; + if (rproc->state == RPROC_ATTACHED) { + ret = rproc_detach(rproc); + if (ret) { + dev_err(kproc->dev, "failed to detach rproc, ret = %d\n", ret); + return; + } + } + rproc_del(rproc); k3_r5_reserved_mem_exit(kproc); From 2eab5efeb4d644d9c94e29c3cbb35a47f715bffd Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Sun, 13 Feb 2022 14:12:45 -0600 Subject: [PATCH 17/22] remoteproc: k3-dsp: Refactor mbox request code in start Refactor out the mailbox request and associated ping logic code from k3_dsp_rproc_start() function into its own separate function so that it can be re-used in the soon to be added .attach() ops callback. Signed-off-by: Suman Anna Reviewed-by: Mathieu Poirier Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220213201246.25952-5-s-anna@ti.com --- drivers/remoteproc/ti_k3_dsp_remoteproc.c | 67 ++++++++++++++--------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index 939c5d90b562..b3ee03da5569 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -2,7 +2,7 @@ /* * TI K3 DSP Remote Processor(s) driver * - * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ * Suman Anna */ @@ -216,6 +216,43 @@ lreset: 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)) { + ret = -EBUSY; + dev_err(dev, "mbox_request_channel failed: %ld\n", + PTR_ERR(kproc->mbox)); + return 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); + 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 @@ -273,37 +310,13 @@ 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 mbox_client *client = &kproc->client; struct device *dev = kproc->dev; u32 boot_addr; 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)) { - ret = -EBUSY; - dev_err(dev, "mbox_request_channel failed: %ld\n", - PTR_ERR(kproc->mbox)); + ret = k3_dsp_rproc_request_mbox(rproc); + if (ret) return 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); - goto put_mbox; - } boot_addr = rproc->bootaddr; if (boot_addr & (kproc->data->boot_align_addr - 1)) { From b8431920391d36c273f63a29eab0dfc7e884dd17 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Sun, 13 Feb 2022 14:12:46 -0600 Subject: [PATCH 18/22] remoteproc: k3-dsp: Add support for IPC-only mode for all K3 DSPs Add support to the K3 DSP remoteproc driver to configure all the C66x and C71x cores on J721E SoCs to be either in IPC-only mode or the traditional remoteproc mode. The IPC-only mode expects that the remote processors are already booted by the bootloader, and only perform the minimum steps required to initialize and deinitialize the virtio IPC transports. The remoteproc mode allows the kernel remoteproc driver to do the regular load and boot and other device management operations for a DSP. The IPC-only mode for a DSP is detected and configured at driver probe time by querying the System Firmware for the DSP power and reset state and/or status and making sure that the DSP is indeed started by the bootloaders, otherwise the device is configured for remoteproc mode. Support for IPC-only mode is achieved through .attach(), .detach() and .get_loaded_rsc_table() callback ops and zeroing out the regular rproc ops .prepare(), .unprepare(), .start() and .stop(). The resource table follows a design-by-contract approach and is expected to be at the base of the DDR firmware region reserved for each remoteproc, it is mostly expected to contain only the virtio device and trace resource entries. NOTE: The driver cannot configure a DSP core for remoteproc mode by any means without rebooting the kernel if that DSP core has been started by a bootloader. This is the current desired behavior and can be enhanced in the future if the feature is needed. Signed-off-by: Suman Anna Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220213201246.25952-6-s-anna@ti.com --- drivers/remoteproc/ti_k3_dsp_remoteproc.c | 141 +++++++++++++++++++--- 1 file changed, 124 insertions(+), 17 deletions(-) diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index b3ee03da5569..eb9c64f7b9b4 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -260,7 +260,8 @@ static int k3_dsp_rproc_request_mbox(struct rproc *rproc) * 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. + * actually let the C66x DSP cores run. This callback is invoked only in + * remoteproc mode. */ static int k3_dsp_rproc_prepare(struct rproc *rproc) { @@ -284,7 +285,7 @@ static int k3_dsp_rproc_prepare(struct rproc *rproc) * 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. + * reset. This callback is invoked only in remoteproc mode. */ static int k3_dsp_rproc_unprepare(struct rproc *rproc) { @@ -305,7 +306,7 @@ static int k3_dsp_rproc_unprepare(struct rproc *rproc) * * This function will be invoked only after the firmware for this rproc * was loaded, parsed successfully, and all of its resource requirements - * were met. + * were met. This callback is invoked only in remoteproc mode. */ static int k3_dsp_rproc_start(struct rproc *rproc) { @@ -346,7 +347,7 @@ put_mbox: * Stop the DSP remote processor. * * This function puts the DSP processor into reset, and finishes processing - * of any pending messages. + * of any pending messages. This callback is invoked only in remoteproc mode. */ static int k3_dsp_rproc_stop(struct rproc *rproc) { @@ -359,6 +360,78 @@ static int k3_dsp_rproc_stop(struct rproc *rproc) return 0; } +/* + * Attach to a running DSP remote processor (IPC-only mode) + * + * This rproc attach callback only needs to request the mailbox, the remote + * processor is already booted, 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. + */ +static int k3_dsp_rproc_attach(struct rproc *rproc) +{ + struct k3_dsp_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + int ret; + + ret = k3_dsp_rproc_request_mbox(rproc); + if (ret) + return ret; + + dev_info(dev, "DSP initialized in IPC-only mode\n"); + return 0; +} + +/* + * Detach from a running DSP remote processor (IPC-only mode) + * + * This rproc detach callback performs the opposite operation to attach callback + * and only needs to release the mailbox, 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. + */ +static int k3_dsp_rproc_detach(struct rproc *rproc) +{ + struct k3_dsp_rproc *kproc = rproc->priv; + struct device *dev = kproc->dev; + + mbox_free_channel(kproc->mbox); + dev_info(dev, "DSP deinitialized in IPC-only mode\n"); + 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 @@ -605,6 +678,7 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev) struct k3_dsp_rproc *kproc; struct rproc *rproc; const char *fw_name; + bool p_state = false; int ret = 0; int ret1; @@ -683,19 +757,43 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev) goto release_tsp; } - /* - * 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) { - dev_err(dev, "failed to get reset status, status = %d\n", - ret); - goto release_mem; - } else if (ret == 0) { - dev_warn(dev, "local reset is deasserted for device\n"); - k3_dsp_rproc_reset(kproc); + ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id, + NULL, &p_state); + if (ret) { + dev_err(dev, "failed to get initial state, mode cannot be determined, ret = %d\n", + ret); + goto release_mem; + } + + /* configure J721E devices for either remoteproc or IPC-only mode */ + 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) { + dev_err(dev, "failed to get reset status, status = %d\n", + ret); + goto release_mem; + } else if (ret == 0) { + dev_warn(dev, "local reset is deasserted for device\n"); + k3_dsp_rproc_reset(kproc); + } } } @@ -730,9 +828,18 @@ free_rproc: static int k3_dsp_rproc_remove(struct platform_device *pdev) { struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev); + struct rproc *rproc = kproc->rproc; struct device *dev = &pdev->dev; int ret; + if (rproc->state == RPROC_ATTACHED) { + ret = rproc_detach(rproc); + if (ret) { + dev_err(dev, "failed to detach proc, ret = %d\n", ret); + return ret; + } + } + rproc_del(kproc->rproc); ret = ti_sci_proc_release(kproc->tsp); From 841fdd0ac005036972c06ebe2e456a20eea8b9da Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 1 Feb 2022 16:22:02 +0530 Subject: [PATCH 19/22] dt-bindings: remoteproc: qcom: adsp: Convert binding to YAML Convert Qualcomm ADSP/CDSP Remoteproc devicetree binding to YAML. Reviewed-by: Rob Herring Reviewed-by: Stephen Boyd Signed-off-by: Rakesh Pillai Signed-off-by: Manikanta Pubbisetty Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1643712724-12436-2-git-send-email-quic_mpubbise@quicinc.com --- .../bindings/remoteproc/qcom,hexagon-v56.txt | 140 --------------- .../remoteproc/qcom,qcs404-cdsp-pil.yaml | 161 ++++++++++++++++++ .../remoteproc/qcom,sdm845-adsp-pil.yaml | 160 +++++++++++++++++ 3 files changed, 321 insertions(+), 140 deletions(-) delete mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt b/Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt deleted file mode 100644 index 1337a3d93d35..000000000000 --- a/Documentation/devicetree/bindings/remoteproc/qcom,hexagon-v56.txt +++ /dev/null @@ -1,140 +0,0 @@ -Qualcomm Technology Inc. Hexagon v56 Peripheral Image Loader - -This document defines the binding for a component that loads and boots firmware -on the Qualcomm Technology Inc. Hexagon v56 core. - -- compatible: - Usage: required - Value type: - Definition: must be one of: - "qcom,qcs404-cdsp-pil", - "qcom,sdm845-adsp-pil" - -- reg: - Usage: required - Value type: - Definition: must specify the base address and size of the qdsp6ss register - -- interrupts-extended: - Usage: required - Value type: - Definition: must list the watchdog, fatal IRQs ready, handover and - stop-ack IRQs - -- interrupt-names: - Usage: required - Value type: - Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack" - -- clocks: - Usage: required - Value type: - Definition: List of phandles and clock specifier pairs for the Hexagon, - per clock-names below. - -- clock-names: - Usage: required for SDM845 ADSP - Value type: - Definition: List of clock input name strings sorted in the same - order as the clocks property. Definition must have - "xo", "sway_cbcr", "lpass_ahbs_aon_cbcr", - "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep" - and "qdsp6ss_core". - -- clock-names: - Usage: required for QCS404 CDSP - Value type: - Definition: List of clock input name strings sorted in the same - order as the clocks property. Definition must have - "xo", "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", - "q6ss_master", "q6_axim". - -- power-domains: - Usage: required - Value type: - Definition: reference to cx power domain node. - -- resets: - Usage: required - Value type: - Definition: reference to the list of resets for the Hexagon. - -- reset-names: - Usage: required for SDM845 ADSP - Value type: - Definition: must be "pdc_sync" and "cc_lpass" - -- reset-names: - Usage: required for QCS404 CDSP - Value type: - Definition: must be "restart" - -- qcom,halt-regs: - Usage: required - Value type: - Definition: a phandle reference to a syscon representing TCSR followed - by the offset within syscon for Hexagon halt register. - -- memory-region: - Usage: required - Value type: - Definition: reference to the reserved-memory for the firmware - -- qcom,smem-states: - Usage: required - Value type: - Definition: reference to the smem state for requesting the Hexagon to - shut down - -- qcom,smem-state-names: - Usage: required - Value type: - Definition: must be "stop" - - -= SUBNODES -The adsp node may have an subnode named "glink-edge" that describes the -communication edge, channels and devices related to the Hexagon. -See ../soc/qcom/qcom,glink.txt for details on how to describe these. - -= EXAMPLE -The following example describes the resources needed to boot control the -ADSP, as it is found on SDM845 boards. - - remoteproc@17300000 { - compatible = "qcom,sdm845-adsp-pil"; - reg = <0x17300000 0x40c>; - - interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>, - <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, - <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, - <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, - <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "wdog", "fatal", "ready", - "handover", "stop-ack"; - - clocks = <&rpmhcc RPMH_CXO_CLK>, - <&gcc GCC_LPASS_SWAY_CLK>, - <&lpasscc LPASS_Q6SS_AHBS_AON_CLK>, - <&lpasscc LPASS_Q6SS_AHBM_AON_CLK>, - <&lpasscc LPASS_QDSP6SS_XO_CLK>, - <&lpasscc LPASS_QDSP6SS_SLEEP_CLK>, - <&lpasscc LPASS_QDSP6SS_CORE_CLK>; - clock-names = "xo", "sway_cbcr", - "lpass_ahbs_aon_cbcr", - "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", - "qdsp6ss_sleep", "qdsp6ss_core"; - - power-domains = <&rpmhpd SDM845_CX>; - - resets = <&pdc_reset PDC_AUDIO_SYNC_RESET>, - <&aoss_reset AOSS_CC_LPASS_RESTART>; - reset-names = "pdc_sync", "cc_lpass"; - - qcom,halt-regs = <&tcsr_mutex_regs 0x22000>; - - memory-region = <&pil_adsp_mem>; - - qcom,smem-states = <&adsp_smp2p_out 0>; - qcom,smem-state-names = "stop"; - }; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml new file mode 100644 index 000000000000..31413cfe10db --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-cdsp-pil.yaml @@ -0,0 +1,161 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,qcs404-cdsp-pil.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm QCS404 CDSP Peripheral Image Loader + +maintainers: + - Bjorn Andersson + +description: + This document defines the binding for a component that loads and boots firmware + on the Qualcomm Technology Inc. CDSP (Compute DSP). + +properties: + compatible: + enum: + - qcom,qcs404-cdsp-pil + + reg: + maxItems: 1 + description: + The base address and size of the qdsp6ss register + + interrupts: + items: + - description: Watchdog interrupt + - description: Fatal interrupt + - description: Ready interrupt + - description: Handover interrupt + - description: Stop acknowledge interrupt + + interrupt-names: + items: + - const: wdog + - const: fatal + - const: ready + - const: handover + - const: stop-ack + + clocks: + items: + - description: XO clock + - description: SWAY clock + - description: TBU clock + - description: BIMC clock + - description: AHB AON clock + - description: Q6SS SLAVE clock + - description: Q6SS MASTER clock + - description: Q6 AXIM clock + + clock-names: + items: + - const: xo + - const: sway + - const: tbu + - const: bimc + - const: ahb_aon + - const: q6ss_slave + - const: q6ss_master + - const: q6_axim + + power-domains: + items: + - description: CX power domain + + resets: + items: + - description: AOSS restart + + reset-names: + items: + - const: restart + + memory-region: + maxItems: 1 + description: Reference to the reserved-memory for the Hexagon core + + qcom,halt-regs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + Phandle reference to a syscon representing TCSR followed by the + three offsets within syscon for q6, modem and nc halt registers. + + qcom,smem-states: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: States used by the AP to signal the Hexagon core + items: + - description: Stop the modem + + qcom,smem-state-names: + $ref: /schemas/types.yaml#/definitions/string + description: The names of the state bits used for SMP2P output + items: + - const: stop + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - power-domains + - resets + - reset-names + - qcom,halt-regs + - memory-region + - qcom,smem-states + - qcom,smem-state-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + remoteproc@b00000 { + compatible = "qcom,qcs404-cdsp-pil"; + reg = <0x00b00000 0x4040>; + + interrupts-extended = <&intc GIC_SPI 229 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&xo_board>, + <&gcc GCC_CDSP_CFG_AHB_CLK>, + <&gcc GCC_CDSP_TBU_CLK>, + <&gcc GCC_BIMC_CDSP_CLK>, + <&turingcc TURING_WRAPPER_AON_CLK>, + <&turingcc TURING_Q6SS_AHBS_AON_CLK>, + <&turingcc TURING_Q6SS_AHBM_AON_CLK>, + <&turingcc TURING_Q6SS_Q6_AXIM_CLK>; + clock-names = "xo", + "sway", + "tbu", + "bimc", + "ahb_aon", + "q6ss_slave", + "q6ss_master", + "q6_axim"; + + power-domains = <&rpmhpd SDM845_CX>; + + resets = <&gcc GCC_CDSP_RESTART>; + reset-names = "restart"; + + qcom,halt-regs = <&tcsr 0x19004>; + + memory-region = <&cdsp_fw_mem>; + + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + }; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml new file mode 100644 index 000000000000..1535bbbe25da --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sdm845-adsp-pil.yaml @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,sdm845-adsp-pil.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM845 ADSP Peripheral Image Loader + +maintainers: + - Bjorn Andersson + +description: + This document defines the binding for a component that loads and boots firmware + on the Qualcomm Technology Inc. ADSP. + +properties: + compatible: + enum: + - qcom,sdm845-adsp-pil + + reg: + maxItems: 1 + description: + The base address and size of the qdsp6ss register + + interrupts: + items: + - description: Watchdog interrupt + - description: Fatal interrupt + - description: Ready interrupt + - description: Handover interrupt + - description: Stop acknowledge interrupt + + interrupt-names: + items: + - const: wdog + - const: fatal + - const: ready + - const: handover + - const: stop-ack + + clocks: + items: + - description: XO clock + - description: SWAY clock + - description: LPASS AHBS AON clock + - description: LPASS AHBM AON clock + - description: QDSP XO clock + - description: Q6SP6SS SLEEP clock + - description: Q6SP6SS CORE clock + + clock-names: + items: + - const: xo + - const: sway_cbcr + - const: lpass_ahbs_aon_cbcr + - const: lpass_ahbm_aon_cbcr + - const: qdsp6ss_xo + - const: qdsp6ss_sleep + - const: qdsp6ss_core + + power-domains: + items: + - description: CX power domain + + resets: + items: + - description: PDC AUDIO SYNC RESET + - description: CC LPASS restart + + reset-names: + items: + - const: pdc_sync + - const: cc_lpass + + memory-region: + maxItems: 1 + description: Reference to the reserved-memory for the Hexagon core + + qcom,halt-regs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + Phandle reference to a syscon representing TCSR followed by the + three offsets within syscon for q6, modem and nc halt registers. + + qcom,smem-states: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: States used by the AP to signal the Hexagon core + items: + - description: Stop the modem + + qcom,smem-state-names: + $ref: /schemas/types.yaml#/definitions/string + description: The names of the state bits used for SMP2P output + items: + - const: stop + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - power-domains + - resets + - reset-names + - qcom,halt-regs + - memory-region + - qcom,smem-states + - qcom,smem-state-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + #include + remoteproc@17300000 { + compatible = "qcom,sdm845-adsp-pil"; + reg = <0x17300000 0x40c>; + + interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", + "handover", "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_LPASS_SWAY_CLK>, + <&lpasscc LPASS_Q6SS_AHBS_AON_CLK>, + <&lpasscc LPASS_Q6SS_AHBM_AON_CLK>, + <&lpasscc LPASS_QDSP6SS_XO_CLK>, + <&lpasscc LPASS_QDSP6SS_SLEEP_CLK>, + <&lpasscc LPASS_QDSP6SS_CORE_CLK>; + clock-names = "xo", "sway_cbcr", + "lpass_ahbs_aon_cbcr", + "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", + "qdsp6ss_sleep", "qdsp6ss_core"; + + power-domains = <&rpmhpd SDM845_CX>; + + resets = <&pdc_reset PDC_AUDIO_SYNC_RESET>, + <&aoss_reset AOSS_CC_LPASS_RESTART>; + reset-names = "pdc_sync", "cc_lpass"; + + qcom,halt-regs = <&tcsr_mutex_regs 0x22000>; + + memory-region = <&pil_adsp_mem>; + + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + }; From 2630504894e8de12295dd4dc6062fd432765dcc5 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 1 Feb 2022 16:22:03 +0530 Subject: [PATCH 20/22] dt-bindings: remoteproc: qcom: Add SC7280 WPSS support Add WPSS PIL loading support for SC7280 SoCs. Reviewed-by: Rob Herring Reviewed-by: Stephen Boyd Signed-off-by: Rakesh Pillai Signed-off-by: Manikanta Pubbisetty Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1643712724-12436-3-git-send-email-quic_mpubbise@quicinc.com --- .../remoteproc/qcom,sc7280-wpss-pil.yaml | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml new file mode 100644 index 000000000000..2424de733ee4 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,sc7280-wpss-pil.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SC7280 WPSS Peripheral Image Loader + +maintainers: + - Bjorn Andersson + +description: + This document defines the binding for a component that loads and boots firmware + on the Qualcomm Technology Inc. WPSS. + +properties: + compatible: + enum: + - qcom,sc7280-wpss-pil + + reg: + maxItems: 1 + description: + The base address and size of the qdsp6ss register + + interrupts: + items: + - description: Watchdog interrupt + - description: Fatal interrupt + - description: Ready interrupt + - description: Handover interrupt + - description: Stop acknowledge interrupt + - description: Shutdown acknowledge interrupt + + interrupt-names: + items: + - const: wdog + - const: fatal + - const: ready + - const: handover + - const: stop-ack + - const: shutdown-ack + + clocks: + items: + - description: GCC WPSS AHB BDG Master clock + - description: GCC WPSS AHB clock + - description: GCC WPSS RSCP clock + - description: XO clock + + clock-names: + items: + - const: ahb_bdg + - const: ahb + - const: rscp + - const: xo + + power-domains: + items: + - description: CX power domain + - description: MX power domain + + power-domain-names: + items: + - const: cx + - const: mx + + resets: + items: + - description: AOSS restart + - description: PDC SYNC + + reset-names: + items: + - const: restart + - const: pdc_sync + + memory-region: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the reserved-memory for the Hexagon core + + firmware-name: + $ref: /schemas/types.yaml#/definitions/string + description: + The name of the firmware which should be loaded for this remote + processor. + + qcom,halt-regs: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + Phandle reference to a syscon representing TCSR followed by the + three offsets within syscon for q6, modem and nc halt registers. + + qcom,qmp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AOSS side-channel message RAM. + + qcom,smem-states: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: States used by the AP to signal the Hexagon core + items: + - description: Stop the modem + + qcom,smem-state-names: + $ref: /schemas/types.yaml#/definitions/string + description: The names of the state bits used for SMP2P output + items: + - const: stop + + glink-edge: + type: object + description: | + Qualcomm G-Link subnode which represents communication edge, channels + and devices related to the ADSP. + + properties: + interrupts: + items: + - description: IRQ from WPSS to GLINK + + mboxes: + items: + - description: Mailbox for communication between APPS and WPSS + + label: + description: The names of the state bits used for SMP2P output + items: + - const: wpss + + qcom,remote-pid: + $ref: /schemas/types.yaml#/definitions/uint32 + description: ID of the shared memory used by GLINK for communication with WPSS + maxItems: 1 + + required: + - interrupts + - mboxes + - label + - qcom,remote-pid + + additionalProperties: false + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - power-domains + - power-domain-names + - resets + - reset-names + - qcom,halt-regs + - memory-region + - qcom,qmp + - qcom,smem-states + - qcom,smem-state-names + - glink-edge + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + #include + remoteproc@8a00000 { + compatible = "qcom,sc7280-wpss-pil"; + reg = <0x08a00000 0x10000>; + + interrupts-extended = <&intc GIC_SPI 587 IRQ_TYPE_EDGE_RISING>, + <&wpss_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&wpss_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&wpss_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&wpss_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&wpss_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&gcc GCC_WPSS_AHB_BDG_MST_CLK>, + <&gcc GCC_WPSS_AHB_CLK>, + <&gcc GCC_WPSS_RSCP_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ahb_bdg", "ahb", + "rscp", "xo"; + + power-domains = <&rpmhpd SC7280_CX>, + <&rpmhpd SC7280_MX>; + power-domain-names = "cx", "mx"; + + memory-region = <&wpss_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&wpss_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + resets = <&aoss_reset AOSS_CC_WCSS_RESTART>, + <&pdc_reset PDC_WPSS_SYNC_RESET>; + reset-names = "restart", "pdc_sync"; + + qcom,halt-regs = <&tcsr_mutex 0x37000>; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_WPSS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_WPSS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "wpss"; + qcom,remote-pid = <13>; + }; + }; From 358b586fb3bc308a23b284ab087de145b5344ccc Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 1 Feb 2022 16:22:04 +0530 Subject: [PATCH 21/22] remoteproc: qcom: q6v5_wpss: Add support for sc7280 WPSS Add support for PIL loading of WPSS processor for SC7280 - WPSS boot will be requested by the wifi driver and hence disable auto-boot for WPSS. - Add a separate shutdown sequence handler for WPSS. - Add multiple power-domain voting support - Parse firmware-name from dtsi entry Reviewed-by: Stephen Boyd Signed-off-by: Rakesh Pillai Signed-off-by: Manikanta Pubbisetty Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1643712724-12436-4-git-send-email-quic_mpubbise@quicinc.com --- drivers/remoteproc/qcom_q6v5_adsp.c | 227 ++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 16 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 7c02bc132247..2f3b9f54251e 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -32,6 +32,7 @@ /* time out value */ #define ACK_TIMEOUT 1000 +#define ACK_TIMEOUT_US 1000000 #define BOOT_FSM_TIMEOUT 10000 /* mask values */ #define EVB_MASK GENMASK(27, 4) @@ -51,6 +52,8 @@ #define QDSP6SS_CORE_CBCR 0x20 #define QDSP6SS_SLEEP_CBCR 0x3c +#define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3 + struct adsp_pil_data { int crash_reason_smem; const char *firmware_name; @@ -58,9 +61,13 @@ struct adsp_pil_data { const char *ssr_name; const char *sysmon_name; int ssctl_id; + bool is_wpss; + bool auto_boot; const char **clk_ids; int num_clks; + const char **proxy_pd_names; + const char *load_state; }; struct qcom_adsp { @@ -93,11 +100,151 @@ struct qcom_adsp { void *mem_region; size_t mem_size; + struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX]; + size_t proxy_pd_count; + struct qcom_rproc_glink glink_subdev; struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; + + int (*shutdown)(struct qcom_adsp *adsp); }; +static int qcom_rproc_pds_attach(struct device *dev, struct qcom_adsp *adsp, + const char **pd_names) +{ + struct device **devs = adsp->proxy_pds; + size_t num_pds = 0; + int ret; + int i; + + if (!pd_names) + return 0; + + /* Handle single power domain */ + if (dev->pm_domain) { + devs[0] = dev; + pm_runtime_enable(dev); + return 1; + } + + while (pd_names[num_pds]) + num_pds++; + + if (num_pds > ARRAY_SIZE(adsp->proxy_pds)) + return -E2BIG; + + for (i = 0; i < num_pds; i++) { + devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]); + if (IS_ERR_OR_NULL(devs[i])) { + ret = PTR_ERR(devs[i]) ? : -ENODATA; + goto unroll_attach; + } + } + + return num_pds; + +unroll_attach: + for (i--; i >= 0; i--) + dev_pm_domain_detach(devs[i], false); + + return ret; +} + +static void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds, + size_t pd_count) +{ + struct device *dev = adsp->dev; + int i; + + /* Handle single power domain */ + if (dev->pm_domain && pd_count) { + pm_runtime_disable(dev); + return; + } + + for (i = 0; i < pd_count; i++) + dev_pm_domain_detach(pds[i], false); +} + +static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds, + size_t pd_count) +{ + int ret; + int i; + + for (i = 0; i < pd_count; i++) { + dev_pm_genpd_set_performance_state(pds[i], INT_MAX); + ret = pm_runtime_get_sync(pds[i]); + if (ret < 0) { + pm_runtime_put_noidle(pds[i]); + dev_pm_genpd_set_performance_state(pds[i], 0); + goto unroll_pd_votes; + } + } + + return 0; + +unroll_pd_votes: + for (i--; i >= 0; i--) { + dev_pm_genpd_set_performance_state(pds[i], 0); + pm_runtime_put(pds[i]); + } + + return ret; +} + +static void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds, + size_t pd_count) +{ + int i; + + for (i = 0; i < pd_count; i++) { + dev_pm_genpd_set_performance_state(pds[i], 0); + pm_runtime_put(pds[i]); + } +} + +static int qcom_wpss_shutdown(struct qcom_adsp *adsp) +{ + unsigned int val; + + regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 1); + + /* Wait for halt ACK from QDSP6 */ + regmap_read_poll_timeout(adsp->halt_map, + adsp->halt_lpass + LPASS_HALTACK_REG, val, + val, 1000, ACK_TIMEOUT_US); + + /* Assert the WPSS PDC Reset */ + reset_control_assert(adsp->pdc_sync_reset); + + /* Place the WPSS processor into reset */ + reset_control_assert(adsp->restart); + + /* wait after asserting subsystem restart from AOSS */ + usleep_range(200, 205); + + /* Remove the WPSS reset */ + reset_control_deassert(adsp->restart); + + /* De-assert the WPSS PDC Reset */ + reset_control_deassert(adsp->pdc_sync_reset); + + usleep_range(100, 105); + + clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks); + + regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0); + + /* Wait for halt ACK from QDSP6 */ + regmap_read_poll_timeout(adsp->halt_map, + adsp->halt_lpass + LPASS_HALTACK_REG, val, + !val, 1000, ACK_TIMEOUT_US); + + return 0; +} + static int qcom_adsp_shutdown(struct qcom_adsp *adsp) { unsigned long timeout; @@ -193,12 +340,10 @@ static int adsp_start(struct rproc *rproc) if (ret) goto disable_irqs; - dev_pm_genpd_set_performance_state(adsp->dev, INT_MAX); - ret = pm_runtime_get_sync(adsp->dev); - if (ret) { - pm_runtime_put_noidle(adsp->dev); + ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds, + adsp->proxy_pd_count); + if (ret < 0) goto disable_xo_clk; - } ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks); if (ret) { @@ -243,8 +388,7 @@ static int adsp_start(struct rproc *rproc) disable_adsp_clks: clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks); disable_power_domain: - dev_pm_genpd_set_performance_state(adsp->dev, 0); - pm_runtime_put(adsp->dev); + qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); disable_xo_clk: clk_disable_unprepare(adsp->xo); disable_irqs: @@ -258,8 +402,7 @@ static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5) struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5); clk_disable_unprepare(adsp->xo); - dev_pm_genpd_set_performance_state(adsp->dev, 0); - pm_runtime_put(adsp->dev); + qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); } static int adsp_stop(struct rproc *rproc) @@ -272,7 +415,7 @@ static int adsp_stop(struct rproc *rproc) if (ret == -ETIMEDOUT) dev_err(adsp->dev, "timed out on wait\n"); - ret = qcom_adsp_shutdown(adsp); + ret = adsp->shutdown(adsp); if (ret) dev_err(adsp->dev, "failed to shutdown: %d\n", ret); @@ -428,6 +571,7 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) static int adsp_probe(struct platform_device *pdev) { const struct adsp_pil_data *desc; + const char *firmware_name; struct qcom_adsp *adsp; struct rproc *rproc; int ret; @@ -436,12 +580,22 @@ static int adsp_probe(struct platform_device *pdev) if (!desc) return -EINVAL; + firmware_name = desc->firmware_name; + ret = of_property_read_string(pdev->dev.of_node, "firmware-name", + &firmware_name); + if (ret < 0 && ret != -EINVAL) { + dev_err(&pdev->dev, "unable to read firmware-name\n"); + return ret; + } + rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops, - desc->firmware_name, sizeof(*adsp)); + firmware_name, sizeof(*adsp)); if (!rproc) { dev_err(&pdev->dev, "unable to allocate remoteproc\n"); return -ENOMEM; } + + rproc->auto_boot = desc->auto_boot; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); adsp = (struct qcom_adsp *)rproc->priv; @@ -450,6 +604,11 @@ static int adsp_probe(struct platform_device *pdev) adsp->info_name = desc->sysmon_name; platform_set_drvdata(pdev, adsp); + if (desc->is_wpss) + adsp->shutdown = qcom_wpss_shutdown; + else + adsp->shutdown = qcom_adsp_shutdown; + ret = adsp_alloc_memory_region(adsp); if (ret) goto free_rproc; @@ -458,7 +617,13 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto free_rproc; - pm_runtime_enable(adsp->dev); + ret = qcom_rproc_pds_attach(adsp->dev, adsp, + desc->proxy_pd_names); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to attach proxy power domains\n"); + goto free_rproc; + } + adsp->proxy_pd_count = ret; ret = adsp_init_reset(adsp); if (ret) @@ -468,8 +633,8 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto disable_pm; - ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, - qcom_adsp_pil_handover); + ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, + desc->load_state, qcom_adsp_pil_handover); if (ret) goto disable_pm; @@ -490,7 +655,8 @@ static int adsp_probe(struct platform_device *pdev) return 0; disable_pm: - pm_runtime_disable(adsp->dev); + qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + free_rproc: rproc_free(rproc); @@ -507,7 +673,7 @@ static int adsp_remove(struct platform_device *pdev) qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_sysmon_subdev(adsp->sysmon); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); - pm_runtime_disable(adsp->dev); + qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); rproc_free(adsp->rproc); return 0; @@ -519,11 +685,16 @@ static const struct adsp_pil_data adsp_resource_init = { .ssr_name = "lpass", .sysmon_name = "adsp", .ssctl_id = 0x14, + .is_wpss = false, + .auto_boot = true, .clk_ids = (const char*[]) { "sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr", "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL }, .num_clks = 7, + .proxy_pd_names = (const char*[]) { + "cx", NULL + }, }; static const struct adsp_pil_data cdsp_resource_init = { @@ -532,15 +703,39 @@ static const struct adsp_pil_data cdsp_resource_init = { .ssr_name = "cdsp", .sysmon_name = "cdsp", .ssctl_id = 0x17, + .is_wpss = false, + .auto_boot = true, .clk_ids = (const char*[]) { "sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master", "q6_axim", NULL }, .num_clks = 7, + .proxy_pd_names = (const char*[]) { + "cx", NULL + }, +}; + +static const struct adsp_pil_data wpss_resource_init = { + .crash_reason_smem = 626, + .firmware_name = "wpss.mdt", + .ssr_name = "wpss", + .sysmon_name = "wpss", + .ssctl_id = 0x19, + .is_wpss = true, + .auto_boot = false, + .load_state = "wpss", + .clk_ids = (const char*[]) { + "ahb_bdg", "ahb", "rscp", NULL + }, + .num_clks = 3, + .proxy_pd_names = (const char*[]) { + "cx", "mx", NULL + }, }; static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init }, + { .compatible = "qcom,sc7280-wpss-pil", .data = &wpss_resource_init }, { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init }, { }, }; From 59983c74fc42eb2448df693113bf725abbda05f9 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 28 Feb 2022 23:53:59 +0100 Subject: [PATCH 22/22] remoteproc: qcom_q6v5_mss: Create platform device for BAM-DMUX The modem remoteproc on older Qualcomm SoCs (e.g. MSM8916 and MSM8974) implements the BAM-DMUX protocol to allow access to the network data channels of the modem. The hardware/firmware resources required to implement the BAM-DMUX driver are described in an extra node in the device tree (with the compatible "qcom,bam-dmux"). This node logically belongs below the modem remoteproc, so that both control interfaces (rpmsg_wwan_ctrl) and network interfaces (bam_dmux) have a common parent. Unlike other child devices of the modem remoteproc, the bam-dmux device currently does not follow the state of the remoteproc (i.e. it is not added/removed when the remoteproc is started/stopped). However, this is an implementation detail of the bam_dmux driver in Linux that might change in the future. To be flexible for future changes, create a standard platform device specifically only for "qcom,bam-dmux", rather than populating all child nodes. This is also more consistent with the way the other child nodes are handled in the driver. Note: of_platform_device_create() and of_node_put() have NULL-checks internally, so there is no need to check if the "qcom,bam-dmux" node actually exists in the device tree. Signed-off-by: Stephan Gerhold Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20220228225400.146555-2-stephan@gerhold.net --- drivers/remoteproc/qcom_q6v5_mss.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index b9ab91540b00..40f4cd155a5b 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -218,6 +218,7 @@ struct q6v5 { struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_ssr ssr_subdev; struct qcom_sysmon *sysmon; + struct platform_device *bam_dmux; bool need_mem_protection; bool has_alt_reset; bool has_mba_logs; @@ -1849,6 +1850,7 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) static int q6v5_probe(struct platform_device *pdev) { const struct rproc_hexagon_res *desc; + struct device_node *node; struct q6v5 *qproc; struct rproc *rproc; const char *mba_image; @@ -1992,6 +1994,10 @@ static int q6v5_probe(struct platform_device *pdev) if (ret) goto remove_sysmon_subdev; + node = of_get_compatible_child(pdev->dev.of_node, "qcom,bam-dmux"); + qproc->bam_dmux = of_platform_device_create(node, NULL, &pdev->dev); + of_node_put(node); + return 0; remove_sysmon_subdev: @@ -2013,6 +2019,8 @@ static int q6v5_remove(struct platform_device *pdev) struct q6v5 *qproc = platform_get_drvdata(pdev); struct rproc *rproc = qproc->rproc; + if (qproc->bam_dmux) + of_platform_device_destroy(&qproc->bam_dmux->dev, NULL); rproc_del(rproc); qcom_q6v5_deinit(&qproc->q6v5);