On Sun, Jun 08, 2025 at 10:37:40AM +0800, Junhui Liu wrote: >Add initial support for the C906L remote processor found in the Sophgo >CV1800B SoC. The C906L is an asymmetric core typically used to run an >RTOS. This driver enables firmware loading and start/stop control of the >C906L processor via the remoteproc framework. > >The C906L and the main application processor can communicate through >mailboxes [1]. Support for mailbox-based functionality will be added in >a separate patch. > >Link: >https://lore.kernel.org/linux-riscv/20250520-cv18xx-mbox-v4-0-fd4f1c676...@pigmoral.tech/ > [1] >Signed-off-by: Junhui Liu <junhui....@pigmoral.tech> >--- > drivers/remoteproc/Kconfig | 9 ++ > drivers/remoteproc/Makefile | 1 + > drivers/remoteproc/sophgo_cv1800b_c906l.c | 233 ++++++++++++++++++++++++++++++ > 3 files changed, 243 insertions(+) > >diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig >index >83962a114dc9fdb3260e6e922602f2da53106265..7b09a8f00332605ee528ff7c21c31091c10c2bf5 > 100644 >--- a/drivers/remoteproc/Kconfig >+++ b/drivers/remoteproc/Kconfig >@@ -299,6 +299,15 @@ config RCAR_REMOTEPROC > This can be either built-in or a loadable module. > If compiled as module (M), the module name is rcar_rproc. > >+config SOPHGO_CV1800B_C906L >+ tristate "Sophgo CV1800B C906L remoteproc support" >+ depends on ARCH_SOPHGO || COMPILE_TEST >+ help >+ Say y here to support CV1800B C906L remote processor via the remote >+ processor framework. >+ >+ It's safe to say N here. >+ > config ST_REMOTEPROC > tristate "ST remoteproc support" > depends on ARCH_STI >diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile >index >1c7598b8475d6057a3e044b41e3515103b7aa9f1..3c1e9387491cedc9dda8219f1e9130a84538156f > 100644 >--- a/drivers/remoteproc/Makefile >+++ b/drivers/remoteproc/Makefile >@@ -33,6 +33,7 @@ obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o > qcom_wcnss_pil-y += qcom_wcnss.o > qcom_wcnss_pil-y += qcom_wcnss_iris.o > obj-$(CONFIG_RCAR_REMOTEPROC) += rcar_rproc.o >+obj-$(CONFIG_SOPHGO_CV1800B_C906L) += sophgo_cv1800b_c906l.o > obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o > obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o > obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o >diff --git a/drivers/remoteproc/sophgo_cv1800b_c906l.c >b/drivers/remoteproc/sophgo_cv1800b_c906l.c >new file mode 100644 >index >0000000000000000000000000000000000000000..f3c8d8fd4f796d0cf64f8ab0dd797e017b8e8be7 >--- /dev/null >+++ b/drivers/remoteproc/sophgo_cv1800b_c906l.c >@@ -0,0 +1,233 @@ >+// SPDX-License-Identifier: GPL-2.0-or-later >+/* >+ * Copyright (C) 2025 Junhui Liu <junhui....@pigmoral.tech> >+ */ >+ >+#include <linux/mfd/syscon.h> >+#include <linux/module.h> >+#include <linux/of_device.h> >+#include <linux/of_reserved_mem.h> >+#include <linux/platform_device.h> >+#include <linux/remoteproc.h> >+#include <linux/reset.h> >+#include <linux/regmap.h> >+ >+#include "remoteproc_internal.h" >+ >+#define CV1800B_SYS_C906L_CTRL_REG 0x04 >+#define CV1800B_SYS_C906L_CTRL_EN BIT(13)
Align the format. '#include <linux/bits.h>' should be added for BIT >+ >+#define CV1800B_SYS_C906L_BOOTADDR_REG 0x20 >+ >+/** >+ * struct cv1800b_c906l - C906L remoteproc structure >+ * @dev: private pointer to the device >+ * @reset: reset control handle >+ * @rproc: the remote processor handle >+ * @syscon: regmap for accessing security system registers >+ */ >+struct cv1800b_c906l { >+ struct device *dev; >+ struct reset_control *reset; >+ struct rproc *rproc; >+ struct regmap *syscon; >+}; >+ >+static int cv1800b_c906l_mem_alloc(struct rproc *rproc, >+ struct rproc_mem_entry *mem) >+{ >+ void *va; >+ >+ va = ioremap_wc(mem->dma, mem->len); >+ if (IS_ERR_OR_NULL(va)) Use "if (!va)"? >+ return -ENOMEM; >+ >+ /* Update memory entry va */ >+ mem->va = va; >+ >+ return 0; >+} >+ >+static int cv1800b_c906l_mem_release(struct rproc *rproc, >+ struct rproc_mem_entry *mem) >+{ >+ iounmap(mem->va); >+ >+ return 0; >+} >+ >+static int cv1800b_c906l_add_carveout(struct rproc *rproc) >+{ >+ struct device *dev = rproc->dev.parent; >+ struct device_node *np = dev->of_node; >+ struct of_phandle_iterator it; >+ struct rproc_mem_entry *mem; >+ struct reserved_mem *rmem; >+ >+ /* Register associated reserved memory regions */ >+ of_phandle_iterator_init(&it, np, "memory-region", NULL, 0); >+ while (of_phandle_iterator_next(&it) == 0) { >+ rmem = of_reserved_mem_lookup(it.node); >+ if (!rmem) { >+ of_node_put(it.node); >+ return -EINVAL; >+ } Is there a need to handle vdev0buffer? >+ >+ mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)rmem->base, >+ rmem->size, rmem->base, >+ cv1800b_c906l_mem_alloc, >+ cv1800b_c906l_mem_release, >+ it.node->name); >+ >+ if (!mem) { >+ of_node_put(it.node); >+ return -ENOMEM; >+ } >+ >+ rproc_add_carveout(rproc, mem); >+ } >+ >+ return 0; >+} >+ >+static int cv1800b_c906l_prepare(struct rproc *rproc) >+{ >+ struct cv1800b_c906l *priv = rproc->priv; >+ int ret; >+ >+ ret = cv1800b_c906l_add_carveout(rproc); >+ if (ret) >+ return ret; >+ >+ /* >+ * This control bit must be set to enable the C906L remote processor. >+ * Note that once the remote processor is running, merely clearing >+ * this bit will not stop its execution. >+ */ >+ return regmap_update_bits(priv->syscon, CV1800B_SYS_C906L_CTRL_REG, >+ CV1800B_SYS_C906L_CTRL_EN, >+ CV1800B_SYS_C906L_CTRL_EN); >+} >+ >+static int cv1800b_c906l_start(struct rproc *rproc) >+{ >+ struct cv1800b_c906l *priv = rproc->priv; >+ u32 bootaddr[2]; >+ int ret; >+ >+ bootaddr[0] = lower_32_bits(rproc->bootaddr); >+ bootaddr[1] = upper_32_bits(rproc->bootaddr); >+ >+ ret = regmap_bulk_write(priv->syscon, CV1800B_SYS_C906L_BOOTADDR_REG, >+ bootaddr, ARRAY_SIZE(bootaddr)); >+ if (ret) >+ return ret; >+ >+ return reset_control_deassert(priv->reset); >+} >+ >+static int cv1800b_c906l_stop(struct rproc *rproc) >+{ >+ struct cv1800b_c906l *priv = rproc->priv; >+ >+ return reset_control_assert(priv->reset); >+} >+ >+static int cv1800b_c906l_parse_fw(struct rproc *rproc, >+ const struct firmware *fw) >+{ >+ int ret; >+ >+ ret = rproc_elf_load_rsc_table(rproc, fw); >+ if (ret == -EINVAL) { >+ dev_info(&rproc->dev, "No resource table in elf\n"); >+ ret = 0; >+ } >+ >+ return ret; >+} >+ >+static const struct rproc_ops cv1800b_c906l_ops = { >+ .prepare = cv1800b_c906l_prepare, >+ .start = cv1800b_c906l_start, >+ .stop = cv1800b_c906l_stop, >+ .load = rproc_elf_load_segments, >+ .parse_fw = cv1800b_c906l_parse_fw, >+ .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table, >+ .sanity_check = rproc_elf_sanity_check, >+ .get_boot_addr = rproc_elf_get_boot_addr, Seems your setup does not support attach mode, so better add attach hook and return -ENOTSUPP? >+}; >+ >+static int cv1800b_c906l_probe(struct platform_device *pdev) >+{ >+ struct device *dev = &pdev->dev; >+ struct device_node *np = dev->of_node; >+ struct cv1800b_c906l *priv; >+ struct rproc *rproc; >+ const char *fw_name; >+ int ret; >+ >+ ret = rproc_of_parse_firmware(dev, 0, &fw_name); >+ if (ret) >+ return dev_err_probe(dev, ret, "No firmware filename given\n"); >+ >+ rproc = devm_rproc_alloc(dev, dev_name(dev), &cv1800b_c906l_ops, >+ fw_name, sizeof(*priv)); >+ if (!rproc) >+ return dev_err_probe(dev, -ENOMEM, >+ "unable to allocate remoteproc\n"); >+ >+ rproc->has_iommu = false; >+ >+ priv = rproc->priv; >+ priv->dev = dev; >+ priv->rproc = rproc; >+ >+ priv->syscon = syscon_regmap_lookup_by_phandle(np, "sophgo,syscon"); >+ if (IS_ERR(priv->syscon)) >+ return PTR_ERR(priv->syscon); >+ >+ priv->reset = devm_reset_control_get_exclusive(dev, NULL); >+ if (IS_ERR(priv->reset)) >+ return dev_err_probe(dev, PTR_ERR(priv->reset), >+ "failed to get reset control handle\n"); >+ >+ platform_set_drvdata(pdev, rproc); >+ >+ ret = devm_rproc_add(dev, rproc); >+ if (ret) >+ return dev_err_probe(dev, ret, "rproc_add failed\n"); >+ >+ return 0; >+} >+ >+static void cv1800b_c906l_remove(struct platform_device *pdev) >+{ >+ struct rproc *rproc = platform_get_drvdata(pdev); >+ >+ if (atomic_read(&rproc->power) > 0) >+ rproc_shutdown(rproc); I think the remoteproc framework should block remove to be executed if 'power > 0'. If not, the framework should be enhanced. Regards, Peng