@@ -7,6 +7,7 @@
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/firmware.h>
#include <linux/firmware/imx/sci.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -23,6 +24,7 @@
#include <linux/workqueue.h>
#include "imx_rproc.h"
+#include "remoteproc_elf_helpers.h"
#include "remoteproc_internal.h"
#define IMX7D_SRC_SCR 0x0C
@@ -634,6 +636,38 @@ static struct resource_table *imx_rproc_get_loaded_rsc_table(struct rproc *rproc
return (struct resource_table __force *)priv->rsc_table;
}
+static u64 imx_rproc_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+{
+ struct imx_rproc *priv = rproc->priv;
+ const u8 *elf_data = (void *)fw->data;
+ u8 class = fw_elf_get_class(fw);
+ u64 bootaddr = rproc_elf_get_boot_addr(rproc, fw);
+ const void *shdr;
+ void __iomem *va;
+ u64 offset;
+
+ if (priv->dcfg->devtype == IMX_RPROC_IMX8M) {
+ /*
+ * i.MX8M Cortex-M requires [stack, pc] be put in address
+ * [0, 4], so the da address is 0, size is 8 bytes.
+ */
+ va = (__force void __iomem *)rproc_da_to_va(rproc, 0, 8, NULL);
+ shdr = rproc_elf_find_shdr(rproc, fw, ".interrupts");
+ if (!shdr || !va)
+ return bootaddr;
+ offset = elf_shdr_get_sh_offset(class, shdr);
+
+ /*
+ * Write stack, pc to TCML start address. The TCML region
+ * is marked with ATT_IOMEM, so use writel.
+ */
+ writel(*(u32 *)(elf_data + offset), va);
+ writel(*(u32 *)(elf_data + offset + 4), va + 4);
+ }
+
+ return bootaddr;
+}
+
static const struct rproc_ops imx_rproc_ops = {
.prepare = imx_rproc_prepare,
.attach = imx_rproc_attach,
@@ -647,7 +681,7 @@ static const struct rproc_ops imx_rproc_ops = {
.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
.get_loaded_rsc_table = imx_rproc_get_loaded_rsc_table,
.sanity_check = rproc_elf_sanity_check,
- .get_boot_addr = rproc_elf_get_boot_addr,
+ .get_boot_addr = imx_rproc_get_boot_addr,
};
static int imx_rproc_addr_init(struct imx_rproc *priv,