summaryrefslogtreecommitdiff
path: root/drivers/remoteproc/ti_k3_dsp_rproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc/ti_k3_dsp_rproc.c')
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c90
1 files changed, 83 insertions, 7 deletions
diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index 4937fdd0a7..1fc8193ad9 100644
--- a/drivers/remoteproc/ti_k3_dsp_rproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2018-2020 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
- *
+ * Suman Anna <s-anna@ti.com>
*/
#include <common.h>
@@ -41,9 +41,11 @@ struct k3_dsp_mem {
/**
* struct k3_dsp_boot_data - internal data structure used for boot
* @boot_align_addr: Boot vector address alignment granularity
+ * @uses_lreset: Flag to denote the need for local reset management
*/
struct k3_dsp_boot_data {
u32 boot_align_addr;
+ bool uses_lreset;
};
/**
@@ -62,6 +64,54 @@ struct k3_dsp_privdata {
int num_mems;
};
+/*
+ * 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
+ * memories to be accessed while the local reset is asserted. This function is
+ * used to release the global reset on C66x DSPs to allow loading into the DSP
+ * internal RAMs. This helper function is invoked in k3_dsp_load() before any
+ * actual firmware loading and is undone only in k3_dsp_stop(). The local reset
+ * on C71x cores is a no-op and the global reset cannot be released on C71x
+ * cores until after the firmware images are loaded, so this function does
+ * nothing for C71x cores.
+ */
+static int k3_dsp_prepare(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+ int ret;
+
+ /* local reset is no-op on C71x processors */
+ if (!data->uses_lreset)
+ return 0;
+
+ ret = ti_sci_proc_power_domain_on(&dsp->tsp);
+ if (ret)
+ dev_err(dev, "cannot enable internal RAM loading, ret = %d\n",
+ ret);
+
+ return ret;
+}
+
+/*
+ * This function is the counterpart to k3_dsp_prepare() and is used to assert
+ * the global reset on C66x DSP cores (no-op for C71x DSP cores). This completes
+ * the second step of powering down the C66x DSP cores. The cores themselves
+ * are halted through the local reset in first step. This function is invoked
+ * in k3_dsp_stop() after the local reset is asserted.
+ */
+static int k3_dsp_unprepare(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+
+ /* local reset is no-op on C71x processors */
+ if (!data->uses_lreset)
+ return 0;
+
+ return ti_sci_proc_power_domain_off(&dsp->tsp);
+}
+
/**
* k3_dsp_load() - Load up the Remote processor image
* @dev: rproc device pointer
@@ -82,10 +132,17 @@ static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
if (ret)
return ret;
+ ret = k3_dsp_prepare(dev);
+ if (ret) {
+ dev_err(dev, "DSP prepare failed for core %d\n",
+ dsp->tsp.proc_id);
+ goto proc_release;
+ }
+
ret = rproc_elf_load_image(dev, addr, size);
if (ret < 0) {
dev_err(dev, "Loading elf failed %d\n", ret);
- goto proc_release;
+ goto unprepare;
}
boot_vector = rproc_elf_get_boot_addr(dev, addr);
@@ -99,6 +156,9 @@ static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector);
ret = ti_sci_proc_set_config(&dsp->tsp, boot_vector, 0, 0);
+unprepare:
+ if (ret)
+ k3_dsp_unprepare(dev);
proc_release:
ti_sci_proc_release(&dsp->tsp);
return ret;
@@ -113,6 +173,7 @@ proc_release:
static int k3_dsp_start(struct udevice *dev)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -121,13 +182,17 @@ static int k3_dsp_start(struct udevice *dev)
if (ret)
return ret;
- ret = ti_sci_proc_power_domain_on(&dsp->tsp);
- if (ret)
- goto proc_release;
+ if (!data->uses_lreset) {
+ ret = ti_sci_proc_power_domain_on(&dsp->tsp);
+ if (ret)
+ goto proc_release;
+ }
ret = reset_deassert(&dsp->dsp_rst);
- if (ret)
- ti_sci_proc_power_domain_off(&dsp->tsp);
+ if (ret) {
+ if (!data->uses_lreset)
+ ti_sci_proc_power_domain_off(&dsp->tsp);
+ }
proc_release:
ti_sci_proc_release(&dsp->tsp);
@@ -344,6 +409,15 @@ static int k3_dsp_probe(struct udevice *dev)
return ret;
}
+ /*
+ * The DSP local resets are deasserted by default on Power-On-Reset.
+ * Assert the local resets to ensure the DSPs don't execute bogus code
+ * in .load() callback when the module reset is released to support
+ * internal memory loading. This is needed for C66x DSPs, and is a
+ * no-op on C71x DSPs.
+ */
+ reset_assert(&dsp->dsp_rst);
+
dev_dbg(dev, "Remoteproc successfully probed\n");
return 0;
@@ -360,10 +434,12 @@ static int k3_dsp_remove(struct udevice *dev)
static const struct k3_dsp_boot_data c66_data = {
.boot_align_addr = SZ_1K,
+ .uses_lreset = true,
};
static const struct k3_dsp_boot_data c71_data = {
.boot_align_addr = SZ_2M,
+ .uses_lreset = false,
};
static const struct udevice_id k3_dsp_ids[] = {