diff options
Diffstat (limited to 'drivers/remoteproc/remoteproc_core.c')
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 106 |
1 files changed, 83 insertions, 23 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index ce92ae227aa1..8b5a3465d23e 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -72,6 +72,23 @@ static const char *rproc_crash_to_string(enum rproc_crash_type type) } /* + * rproc_memcpy() - memcpy verison for remoteproc usage + * @flags: + * - 0 means to DA + * - 1 means from DA + * + */ +void *rproc_memcpy(struct rproc *rproc, void *dest, + const void *src, size_t count, int flags) +{ + if (rproc->ops->memcpy) + return rproc->ops->memcpy(rproc, dest, src, count, flags); + + return memcpy(dest, src, count); +} +EXPORT_SYMBOL(rproc_memcpy); + +/* * This is the IOMMU fault handler we register with the IOMMU API * (when relevant; not all remote processors access memory through * an IOMMU). @@ -1359,8 +1376,19 @@ reset_table_ptr: return ret; } -/* - * take a firmware and boot a remote processor with it. +/** + * rproc_fw_boot() - boot specified remote processor according to specified + * firmware + * @rproc: handle of a remote processor + * @fw: pointer on firmware to handle + * + * Handle resources defined in resource table, load firmware and + * start remote processor. + * + * If firmware pointer fw is NULL, firmware is not handled by remoteproc + * core, but under the responsibility of platform driver. + * + * Returns 0 on success, and an appropriate error value otherwise. */ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) { @@ -1372,7 +1400,11 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) if (ret) return ret; - dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size); + if (fw) + dev_info(dev, "Booting fw image %s, size %zd\n", name, + fw->size); + else + dev_info(dev, "Synchronizing with preloaded co-processor\n"); /* * if enabling an IOMMU isn't relevant for this rproc, this is @@ -1627,7 +1659,8 @@ static void rproc_coredump(struct rproc *rproc) &segment->da, segment->size); memset(data + offset, 0xff, segment->size); } else { - memcpy(data + offset, ptr, segment->size); + rproc_memcpy(rproc, data + offset, ptr, + segment->size, 1); } } @@ -1664,20 +1697,23 @@ int rproc_trigger_recovery(struct rproc *rproc) if (ret) goto unlock_mutex; - /* generate coredump */ - rproc_coredump(rproc); + if (!rproc->skip_fw_load) { + /* generate coredump */ + rproc_coredump(rproc); - /* load firmware */ - ret = request_firmware(&firmware_p, rproc->firmware, dev); - if (ret < 0) { - dev_err(dev, "request_firmware failed: %d\n", ret); - goto unlock_mutex; + /* load firmware */ + ret = request_firmware(&firmware_p, rproc->firmware, dev); + if (ret < 0) { + dev_err(dev, "request_firmware failed: %d\n", ret); + goto unlock_mutex; + } } /* boot the remote processor up again */ ret = rproc_start(rproc, firmware_p); - release_firmware(firmware_p); + if (!rproc->skip_fw_load) + release_firmware(firmware_p); unlock_mutex: mutex_unlock(&rproc->lock); @@ -1719,16 +1755,22 @@ static void rproc_crash_handler_work(struct work_struct *work) * rproc_boot() - boot a remote processor * @rproc: handle of a remote processor * - * Boot a remote processor (i.e. load its firmware, power it on, ...). + * Boot a remote processor (i.e. load its firmware, power it on, ...) from + * different contexts: + * - power off + * - preloaded firmware + * - started before kernel execution + * The different operations are selected thanks to properties defined by + * platform driver. * - * If the remote processor is already powered on, this function immediately - * returns (successfully). + * If the remote processor is already powered on at rproc level, this function + * immediately returns (successfully). * * Returns 0 on success, and an appropriate error value otherwise. */ int rproc_boot(struct rproc *rproc) { - const struct firmware *firmware_p; + const struct firmware *firmware_p = NULL; struct device *dev; int ret; @@ -1759,11 +1801,20 @@ int rproc_boot(struct rproc *rproc) dev_info(dev, "powering up %s\n", rproc->name); - /* load firmware */ - ret = request_firmware(&firmware_p, rproc->firmware, dev); - if (ret < 0) { - dev_err(dev, "request_firmware failed: %d\n", ret); - goto downref_rproc; + if (!rproc->skip_fw_load) { + /* load firmware */ + ret = request_firmware(&firmware_p, rproc->firmware, dev); + if (ret < 0) { + dev_err(dev, "request_firmware failed: %d\n", ret); + goto downref_rproc; + } + } else { + /* + * Set firmware name pointer to null as remoteproc core is not + * in charge of firmware loading + */ + kfree(rproc->firmware); + rproc->firmware = NULL; } ret = rproc_fw_boot(rproc, firmware_p); @@ -1917,8 +1968,17 @@ int rproc_add(struct rproc *rproc) /* create debugfs entries */ rproc_create_debug_dir(rproc); - /* if rproc is marked always-on, request it to boot */ - if (rproc->auto_boot) { + if (rproc->skip_fw_load) { + /* + * If rproc is marked already booted, no need to wait + * for firmware. + * Just handle associated resources and start sub devices + */ + ret = rproc_boot(rproc); + if (ret < 0) + return ret; + } else if (rproc->auto_boot) { + /* if rproc is marked always-on, request it to boot */ ret = rproc_trigger_auto_boot(rproc); if (ret < 0) return ret; |