From: Peng Fan <[email protected]>

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)

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 <[email protected]>
---
 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


Reply via email to