summaryrefslogtreecommitdiff
path: root/drivers/remoteproc/remoteproc_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc/remoteproc_core.c')
-rw-r--r--drivers/remoteproc/remoteproc_core.c106
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;