Enabling M7 Core and Resource Sharing with Linux - Part 2

2024.11.25by debix.io

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;