Re: [PATCH v2 2/3] remoteproc: imx_rproc: Pass bootaddr to SM CPU/LMM reset vector
From: Mathieu Poirier <mathieu.poirier@linaro.org>
Date: 2026-03-30 16:22:39
Also in:
imx, linux-devicetree, linux-remoteproc, lkml
On Fri, Mar 27, 2026 at 10:42:03AM +0800, Peng Fan (OSS) wrote:
From: Peng Fan <peng.fan@nxp.com>
Cortex-M[7,33] processors use a fixed reset vector table format:
0x00 Initial SP value
0x04 Reset vector
0x08 NMI
0x0C ...
...
IRQ[n]
In ELF images, the corresponding layout is:
reset_vectors: --> hardware reset address
.word __stack_end__
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
...
.word UART_IRQHandler
.word SPI_IRQHandler
...
Reset_Handler: --> ELF entry point address
...
The hardware fetches the first two words from reset_vectors and populates
SP with __stack_end__ and PC with Reset_Handler. Execution proceeds from
Reset_Handler.
However, the ELF entry point does not always match the hardware reset
address. For example, on i.MX94 CM33S:
ELF entry point: 0x0ffc211d
hardware reset base: 0x0ffc0000 (default reset value, sw programmable)But why? Why can't the ELF image be set to the right reset base?
quoted hunk ↗ jump to hunk
To derive the correct hardware reset address, the unused lower bits must be masked off. The boot code should apply a SoC-specific mask before programming the reset address registers, e.g.: reset_address = entry & reset_vector_mask Current driver always programs the reset vector as 0. But i.MX94 CM33S's default reset base is 0x0ffc0000, so the correct reset vector must be passed to the SM API; otherwise the M33 Sync core cannot boot successfully. rproc_elf_get_boot_addr() returns the ELF entry point, which is not the hardware reset vector address. To derive the proper reset vector, this patch introduces imx_rproc_get_boot_addr(), which masks the ELF entry point using the SoC‑specific 'reset_vector_mask'. The resulting reset vector address is then passed to the SM CPU/LMM reset vector API calls. Signed-off-by: Peng Fan <peng.fan@nxp.com> --- drivers/remoteproc/imx_rproc.c | 17 ++++++++++++++--- drivers/remoteproc/imx_rproc.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-)diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 0dd80e688b0ea3df4c66e5726884dc86c8a5a881..d8ead42640881bd523d605fa7002935ef6e98077 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c@@ -345,7 +345,7 @@ static int imx_rproc_sm_cpu_start(struct rproc *rproc) const struct imx_rproc_dcfg *dcfg = priv->dcfg; int ret; - ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, 0, true, false, false); + ret = scmi_imx_cpu_reset_vector_set(dcfg->cpuid, rproc->bootaddr, true, false, false); if (ret) { dev_err(priv->dev, "Failed to set reset vector cpuid(%u): %d\n", dcfg->cpuid, ret); return ret;@@ -365,7 +365,7 @@ static int imx_rproc_sm_lmm_start(struct rproc *rproc) * If the remoteproc core can't start the M7, it will already be * handled in imx_rproc_sm_lmm_prepare(). */ - ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, 0); + ret = scmi_imx_lmm_reset_vector_set(dcfg->lmid, dcfg->cpuid, 0, rproc->bootaddr); if (ret) { dev_err(dev, "Failed to set reset vector lmid(%u), cpuid(%u): %d\n", dcfg->lmid, dcfg->cpuid, ret);@@ -739,6 +739,17 @@ imx_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, const struct firmware * return rproc_elf_find_loaded_rsc_table(rproc, fw); } +static u64 imx_rproc_get_boot_addr(struct rproc *rproc, const struct firmware *fw) +{ + struct imx_rproc *priv = rproc->priv; + u32 reset_vector_mask = GENMASK_U32(31, 0); + + if (priv->dcfg->reset_vector_mask) + reset_vector_mask = priv->dcfg->reset_vector_mask; + + return rproc_elf_get_boot_addr(rproc, fw) & reset_vector_mask; +} + static const struct rproc_ops imx_rproc_ops = { .prepare = imx_rproc_prepare, .attach = imx_rproc_attach,@@ -752,7 +763,7 @@ static const struct rproc_ops imx_rproc_ops = { .find_loaded_rsc_table = imx_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,diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index d37e6f90548cec727b4aeb874680b42af85bdbb4..0d7d48352a1091ad24e8e083172ce6da6d26ae10 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h@@ -41,6 +41,8 @@ struct imx_rproc_dcfg { /* For System Manager(SM) based SoCs */ u32 cpuid; /* ID of the remote core */ u32 lmid; /* ID of the Logcial Machine */ + /* reset_vector = elf_entry_addr & reset_vector_mask */ + u32 reset_vector_mask; }; #endif /* _IMX_RPROC_H */-- 2.37.1