3. Modify device driver of the M7 coreimx_rproc.c
--- /drivers/remoteproc/imx_rproc.c
+++ /drivers/remoteproc/imx_rproc.c
@@ -25,6 +25,11 @@
#include "remoteproc_internal.h"
+//add by wei
+#define TCML_ADDR_IMX8M 0x7e0000
+#define TCML_ADDR_IMX8_CM4_1 0x34fe0000
+#define TCML_ADDR_IMX8_CM4_2 0x38fe0000
+
#define IMX7D_SRC_SCR 0x0C
#define IMX7D_ENABLE_M4 BIT(3)
#define IMX7D_SW_M4P_RST BIT(2)
@@ -131,10 +136,37 @@
int num_domains;
struct device **pm_devices;
struct device_link **pm_devices_link;
+ //add by wei
+ u32 m_core_ddr_addr;
+ u32 last_load_addr;
+ u32 m4_start_addr;
};
static struct imx_sc_ipc *ipc_handle;
+// add by wei
+static const struct imx_rproc_att imx_rproc_att_imx8mp[] = {
+ /* dev addr , sys addr , size , flags */
+ /* ITCM */
+ {0x00000000, 0x007E0000, 0x00020000, ATT_OWN},
+ /* OCRAM_S */
+ {0x00180000, 0x00180000, 0x00009000, 0},
+ /* OCRAM */
+ {0x00900000, 0x00900000, 0x00090000, 0},
+ /* QSPI Code - alias */
+ {0x08000000, 0x08000000, 0x08000000, 0},
+ /* DDR (Code) - alias */
+ {0x10000000, 0x40000000, 0x0FFE0000, 0},
+ /* DTCM */
+ {0x20000000, 0x00800000, 0x00020000, ATT_OWN},
+ /* OCRAM_S - alias */
+ {0x20180000, 0x00180000, 0x00008000, ATT_OWN},
+ /* OCRAM */
+ {0x20200000, 0x00900000, 0x00090000, ATT_OWN},
+ /* DDR (Data) */
+ {0x40000000, 0x40000000, 0x80000000, 0},
+};
+
static const struct imx_rproc_att imx_rproc_att_imx8qm[] = {
/* dev addr , sys addr , size , flags */
{ 0x08000000, 0x08000000, 0x10000000, 0},
@@ -284,6 +316,13 @@
.method = IMX_ARM_SMCCC,
};
+static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mp = {
+ .att = imx_rproc_att_imx8mp,
+ .att_size = ARRAY_SIZE(imx_rproc_att_imx8mp),
+ .elf_mem_hook = true,
+ .method = IMX_ARM_SMCCC,
+};
+
static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = {
.src_reg = IMX7D_SRC_SCR,
.src_mask = IMX7D_M4_RST_MASK,
@@ -422,6 +461,54 @@
priv->txdb_ch = NULL;
}
+/*
+"M4 always start up from TCM. The SCU will copy the first 32 bytes of the binary to TCM
+ if the start address is not TCM. The TCM region [0x1FFE0000-0x1FFE001F] is reserved for this purpose."
+ Therefore:
+ For imx8q and imx8x, it is not necessary to copy the stack pointer and reset vector from ddr to tcm.
+ Instead, determine if firmware was loaded into TCM or DDR and provide correct start address to SCU.
+ Like 8M family, DDR4 address is defined in device tree node m4_reserved, m7_reserved, or mcore_reserved
+*/
+static void imx8_set_start_addr(struct rproc *rproc, u32 addr_tcm) {
+ struct imx_rproc *priv = rproc->priv;
+
+ if(priv->m_core_ddr_addr && priv->last_load_addr >= priv->m_core_ddr_addr) {
+ priv->m4_start_addr = priv->m_core_ddr_addr;
+ dev_info(priv->dev, "Setting Cortex M4 start address to DDR 0x%08x\n", priv->m4_start_addr);
+ } else {
+ priv->m4_start_addr = addr_tcm;
+ dev_info(priv->dev, "Setting Cortex M4 start address to TCM 0x%08x\n", priv->m4_start_addr);
+ }
+}
+
+/*
+ Stack pointer and reset vector must be initialized
+*/
+static void imx_8m_setup_stack(struct rproc *rproc)
+{
+ struct imx_rproc *priv = rproc->priv;
+ void __iomem *io_tcml = ioremap(TCML_ADDR_IMX8M, 8);
+
+ //initialize tcml stack pointer and reset vector
+ if(priv->m_core_ddr_addr && priv->last_load_addr >= priv->m_core_ddr_addr) {
+ void __iomem *io_ddr = ioremap(priv->m_core_ddr_addr, 8);
+ dev_info(priv->dev, "Setting up stack pointer and reset vector from firmware in DDR\n");
+ writel(readl(io_ddr), io_tcml);
+ writel(readl(io_ddr + 4), io_tcml + 4);
+ iounmap(io_ddr);
+ } else {
+ dev_info(priv->dev, "Setting up stack pointer and reset vector from firmware in TCML\n");
+ writel(readl(io_tcml), io_tcml);
+ writel(readl(io_tcml + 4), io_tcml + 4);
+ }
+
+ dev_info(priv->dev, "Stack: 0x%x\n", readl(io_tcml));
+ dev_info(priv->dev, "Reset Vector: 0x%x\n", readl(io_tcml + 4));
+
+ iounmap(io_tcml);
+}
+
+
static int imx_rproc_start(struct rproc *rproc)
{
struct imx_rproc *priv = rproc->priv;
@@ -432,10 +519,12 @@
switch (dcfg->method) {
case IMX_DIRECT_MMIO:
+ imx_8m_setup_stack(rproc);
ret = regmap_update_bits(priv->regmap, dcfg->src_reg,
dcfg->src_mask, dcfg->src_start);
break;
case IMX_ARM_SMCCC:
+ imx_8m_setup_stack(rproc);
arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0, 0, 0, 0, 0, &res);
ret = res.a0;
break;
@@ -449,12 +538,15 @@
return imx_rproc_ready(rproc);
}
- if (priv->id == 1)
- ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, true, 0x38fe0000);
- else if (!priv->id)
- ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, true, 0x34fe0000);
- else
+ if (priv->id == 1) {
+ imx8_set_start_addr(rproc, TCML_ADDR_IMX8_CM4_2);
+ ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, true, priv->m4_start_addr);
+ } else if (!priv->id) {
+ imx8_set_start_addr(rproc, TCML_ADDR_IMX8_CM4_1);
+ ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, true, priv->m4_start_addr);
+ } else {
ret = -EINVAL;
+ }
break;
case IMX_IPC_ONLY:
return -ENOTSUPP;
@@ -512,9 +604,9 @@
break;
case IMX_IPC_ONLY:
return -ENOTSUPP;
@@ -512,9 +604,9 @@
break;
case IMX_SCU_API:
if (priv->id == 1)
- ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, false, 0x38fe0000);
+ ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, false, priv->m4_start_addr);
else if (!priv->id)
- ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, false, 0x34fe0000);
+ ret = imx_sc_pm_cpu_start(ipc_handle, priv->rsrc, false, priv->m4_start_addr);
else
ret = -EINVAL;
break;
@@ -677,6 +769,13 @@
else
return -ENOMEM;
+ //get m4/m7 ddr address from device tree
+ if(0 == strcmp(it.node->name, "m4") || 0 == strcmp(it.node->name, "m7")
+ || 0 == strcmp(it.node->name, "m_core")) {
+ priv->m_core_ddr_addr = rmem->base;
+ dev_info(priv->dev, "%s ddr @ 0x%x\n", it.node->name, (u32) rmem->base);
+ }
+
rproc_add_carveout(rproc, mem);
index++;
}
@@ -724,6 +823,21 @@
spin_unlock_irqrestore(&priv->mu_lock, flags);
}
+static u64 imx_rproc_elf_get_boot_addr(struct rproc *rproc,
+ const struct firmware *fw)
+{
+ struct imx_rproc *priv = rproc->priv;
+
+
+ if (!priv->early_boot) {
+ //save the location of the last firmware load for start function
+ priv->last_load_addr = rproc_elf_get_boot_addr(rproc, fw);
+ return (u64)priv->last_load_addr;
+ }
+
+ return 0;
+}
+
static void imx_rproc_kick(struct rproc *rproc, int vqid)
{
struct imx_rproc *priv = rproc->priv;
@@ -788,7 +902,7 @@
.parse_fw = imx_rproc_parse_fw,
.find_loaded_rsc_table = imx_rproc_elf_find_loaded_rsc_table,
.sanity_check = rproc_elf_sanity_check,
- .get_boot_addr = rproc_elf_get_boot_addr,
+ .get_boot_addr = imx_rproc_elf_get_boot_addr,
};
static int imx_rproc_addr_init(struct imx_rproc *priv,
@@ -986,6 +1100,19 @@
return 0;
}
+static int imx_rproc_parse_dt(struct device *dev, struct imx_rproc *priv)
+{
+ int ret = 0;
+
+ if (priv->dcfg->method == IMX_SCU_API) {
+ ret = of_property_read_u32(dev->of_node, "core-index", &priv->id);
+ if (ret)
+ dev_err(dev, "No reg <core index id>\n");
+ }
+
+ return ret;
+}
+
static int imx_rproc_detect_mode(struct imx_rproc *priv)
{
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
@@ -1020,12 +1147,6 @@
dev_err(dev, "No reg <core resource id>\n");
return ret;
}
- ret = of_property_read_u32(dev->of_node, "core-index", &priv->id);
- if (ret) {
- dev_err(dev, "No reg <core index id>\n");
- return ret;
- }
-
priv->proc_nb.notifier_call = imx_rproc_partition_notify;