]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
remoteproc: uclass: Add methods to load firmware to rproc and boot rproc
authorMD Danish Anwar <danishanwar@ti.com>
Thu, 21 Mar 2024 10:28:19 +0000 (15:58 +0530)
committerTom Rini <trini@konsulko.com>
Fri, 22 Mar 2024 19:50:28 +0000 (15:50 -0400)
Add APIs to set a firmware_name to a rproc and boot the rproc with the
same firmware.

Clients can call rproc_set_firmware() API to set firmware_name for a rproc
whereas rproc_boot() will load the firmware set by rproc_set_firmware() to
a buffer by calling request_firmware_into_buf(). rproc_boot() will then
load the firmware file to the remote processor and start the remote
processor.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
Acked-by: Ravi Gunasekaran <r-gunasekaran@ti.com>
Reviewed-by: Roger Quadros <rogerq@kernel.org>
drivers/remoteproc/Kconfig
drivers/remoteproc/rproc-uclass.c
include/remoteproc.h

index 781de530aff174be4f7cde720d66bf6c8560a070..a49802c132329c6596d5fc69020f748f321a74ac 100644 (file)
@@ -102,4 +102,11 @@ config REMOTEPROC_TI_IPU
        help
          Say 'y' here to add support for TI' K3 remoteproc driver.
 
+config REMOTEPROC_MAX_FW_SIZE
+       hex "Maximum size of firmware file that needs to be loaded to the remote processor"
+       default 0x10000
+       help
+         Maximum size of the firmware file (elf, binary) that needs to be
+         loaded to the remote processor.
+
 endmenu
index 28b362c887a656d44ddf0a21d992139c236513e1..aa7f7586a8141eb010fa0711fd9f555d2f5c9039 100644 (file)
@@ -13,6 +13,7 @@
 #include <log.h>
 #include <malloc.h>
 #include <virtio_ring.h>
+#include <fs_loader.h>
 #include <remoteproc.h>
 #include <asm/io.h>
 #include <dm/device-internal.h>
@@ -961,3 +962,106 @@ unsigned long rproc_parse_resource_table(struct udevice *dev, struct rproc *cfg)
 
        return 1;
 }
+
+int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
+{
+       struct dm_rproc_uclass_pdata *uc_pdata;
+       int len;
+       char *p;
+
+       if (!rproc_dev || !fw_name)
+               return -EINVAL;
+
+       uc_pdata = dev_get_uclass_plat(rproc_dev);
+       if (!uc_pdata)
+               return -EINVAL;
+
+       len = strcspn(fw_name, "\n");
+       if (!len) {
+               debug("invalid firmware name\n");
+               return -EINVAL;
+       }
+
+       if (uc_pdata->fw_name)
+               free(uc_pdata->fw_name);
+
+       p = strndup(fw_name, len);
+       if (!p)
+               return -ENOMEM;
+
+       uc_pdata->fw_name = p;
+
+       return 0;
+}
+
+#if CONFIG_IS_ENABLED(FS_LOADER)
+int rproc_boot(struct udevice *rproc_dev)
+{
+       struct dm_rproc_uclass_pdata *uc_pdata;
+       struct udevice *fs_loader;
+       int core_id, ret = 0;
+       char *firmware;
+       void *addr;
+
+       if (!rproc_dev)
+               return -EINVAL;
+
+       uc_pdata = dev_get_uclass_plat(rproc_dev);
+       if (!uc_pdata)
+               return -EINVAL;
+
+       core_id = dev_seq(rproc_dev);
+       firmware = uc_pdata->fw_name;
+       if (!firmware) {
+               debug("No firmware name set for rproc core %d\n", core_id);
+               return -EINVAL;
+       }
+
+       /* Initialize all rproc cores */
+       if (!rproc_is_initialized()) {
+               ret = rproc_init();
+               if (ret) {
+                       debug("rproc_init() failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* Loading firmware to a given address */
+       ret = get_fs_loader(&fs_loader);
+       if (ret) {
+               debug("could not get fs loader: %d\n", ret);
+               return ret;
+       }
+
+       if (CONFIG_REMOTEPROC_MAX_FW_SIZE) {
+               addr = malloc(CONFIG_REMOTEPROC_MAX_FW_SIZE);
+               if (!addr)
+                       return -ENOMEM;
+       } else {
+               debug("CONFIG_REMOTEPROC_MAX_FW_SIZE not defined\n");
+               return -EINVAL;
+       }
+
+       ret = request_firmware_into_buf(fs_loader, firmware, addr, CONFIG_REMOTEPROC_MAX_FW_SIZE,
+                                       0);
+       if (ret < 0) {
+               debug("could not request %s: %d\n", firmware, ret);
+               goto free_buffer;
+       }
+
+       ret = rproc_load(core_id, (ulong)addr, ret);
+       if (ret) {
+               debug("failed to load %s to rproc core %d from addr 0x%08lX err %d\n",
+                     uc_pdata->fw_name, core_id, (ulong)addr, ret);
+               goto free_buffer;
+       }
+
+       ret = rproc_start(core_id);
+       if (ret)
+               debug("failed to start rproc core %d\n", core_id);
+
+free_buffer:
+       free(addr);
+       return ret;
+}
+#endif
index 91a88791a470dd689a753efff0ab7566b0a8da0a..6f8068e14967571eea18522b70fa272697610a41 100644 (file)
@@ -403,6 +403,7 @@ enum rproc_mem_type {
  * @name: Platform-specific way of naming the Remote proc
  * @mem_type: one of 'enum rproc_mem_type'
  * @driver_plat_data: driver specific platform data that may be needed.
+ * @fw_name: firmware name
  *
  * This can be accessed with dev_get_uclass_plat() for any UCLASS_REMOTEPROC
  * device.
@@ -412,6 +413,7 @@ struct dm_rproc_uclass_pdata {
        const char *name;
        enum rproc_mem_type mem_type;
        void *driver_plat_data;
+       char *fw_name;
 };
 
 /**
@@ -705,6 +707,34 @@ unsigned long rproc_parse_resource_table(struct udevice *dev,
 struct resource_table *rproc_find_resource_table(struct udevice *dev,
                                                 unsigned int addr,
                                                 int *tablesz);
+/**
+ * rproc_set_firmware() - assign a new firmware name
+ * @rproc_dev: device for which new firmware name is being assigned
+ * @fw_name: new firmware name to be assigned
+ *
+ * This function allows remoteproc drivers or clients to configure a custom
+ * firmware name. The function does not trigger a remote processor boot,
+ * only sets the firmware name used for a subsequent boot.
+ *
+ * This function sets the fw_name field in uclass pdata of the Remote proc
+ *
+ * Return: 0 on success or a negative value upon failure
+ */
+int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name);
+
+/**
+ * rproc_boot() - boot a remote processor
+ * @rproc_dev: rproc device to boot
+ *
+ * Boot a remote processor (i.e. load its firmware, power it on, ...).
+ *
+ * This function first loads the firmware set in the uclass pdata of Remote
+ * processor to a buffer and then loads firmware to the remote processor
+ * using rproc_load().
+ *
+ * Return: 0 on success, and an appropriate error value otherwise
+ */
+int rproc_boot(struct udevice *rproc_dev);
 #else
 static inline int rproc_init(void) { return -ENOSYS; }
 static inline int rproc_dev_init(int id) { return -ENOSYS; }
@@ -744,6 +774,10 @@ static inline int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
                                           ulong fw_size, ulong *rsc_addr,
                                           ulong *rsc_size)
 { return -ENOSYS; }
+static inline int rproc_set_firmware(struct udevice *rproc_dev, const char *fw_name)
+{ return -ENOSYS; }
+static inline int rproc_boot(struct udevice *rproc_dev)
+{ return -ENOSYS; }
 #endif
 
 #endif /* _RPROC_H_ */