From 3a5d5e08d5a828c86760f281c753e55e80585b41 Mon Sep 17 00:00:00 2001 From: Ari Kimari Date: Fri, 2 Oct 2026 09:11:38 +0300 Subject: [PATCH] arch/arm/imxrt: Add M7 DTCM/ITCM ECC initialization for imxrt118x Add support for Cortex-M33 code to initialize the M7 TCM memories before releasing it to run. The TCM has ECC, which needs to be initialized before the memory is usable for M7. Specifically, the TCM needs to be initialized sequentially in 64-bit writes. Use eDMA4 for this; this is the same mechanism which the NXP MCUXpresso SDK code does. Split imxrt118x_release_cm7() into imxrt118x_prepare_cm7() and imxrt118x_start_cm7(). The TCM ECC initialization is done in imxrt118x_prepare_cm7(), after the M7 has been released from reset and before the M7 is started. Also reset M7_CFG[TCM_SIZE] to the default 256 KiB ITCM / 256 KiB DTCM layout. Co-Authored-By: Jukka Laitinen Signed-off-by: Jukka Laitinen --- arch/arm/src/imxrt/imxrt118x_start_cm7.c | 140 +++++++++++++++++- arch/arm/src/imxrt/imxrt118x_start_cm7.h | 3 +- .../imxrt/imxrt1180-evk/scripts/flash-m33.ld | 7 + .../imxrt1180-evk/src/imxrt_bootloader.c | 7 +- 4 files changed, 152 insertions(+), 5 deletions(-) diff --git a/arch/arm/src/imxrt/imxrt118x_start_cm7.c b/arch/arm/src/imxrt/imxrt118x_start_cm7.c index f614d954d33..7ec3c8a71c9 100644 --- a/arch/arm/src/imxrt/imxrt118x_start_cm7.c +++ b/arch/arm/src/imxrt/imxrt118x_start_cm7.c @@ -36,7 +36,10 @@ #include "arm_internal.h" #include "imxrt118x_ele.h" #include "imxrt118x_start_cm7.h" +#include "imxrt_edma.h" #include "hardware/imxrt_ccm.h" +#include "imxrt_clockconfig_ver3.h" +#include "hardware/rt118x/imxrt118x_edma.h" #include "hardware/rt117x/imxrt117x_dcdc.h" #include "hardware/rt118x/imxrt118x_anadig.h" #include "hardware/rt118x/imxrt118x_blkctrl.h" @@ -50,6 +53,21 @@ #define CCM_M7_ROOT_CONFIG (CCM_CR_CTRL_MUX_SRCSEL(2) | \ CCM_CR_CTRL_DIV(1)) +extern char _sitcm_m7[]; +extern char _eitcm_m7[]; +extern char _sdtcm_m7[]; +extern char _edtcm_m7[]; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Zero fill pattern for the M7 TCM ECC initialization. It lives in flash + * (.rodata), which is readable by eDMA4 and guaranteed to be zero. + */ + +static const uint64_t g_m7_tcm_fill aligned_data(8) = 0; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -169,15 +187,115 @@ static int prepare_m7_power(void) return 0; } +/**************************************************************************** + * Name: imxrt118x_initialize_m7_tcm_ecc + * + * Description: + * Initialize the M7 ITCM and DTCM ECC using eDMA before starting the M7. + * + ****************************************************************************/ + +static int imxrt118x_initialize_m7_tcm_ecc(void) +{ + const uintptr_t starts[] = + { + (uintptr_t)_sitcm_m7, + (uintptr_t)_sdtcm_m7 + }; + + const uintptr_t ends[] = + { + (uintptr_t)_eitcm_m7, + (uintptr_t)_edtcm_m7 + }; + + uintptr_t tcd = IMXRT_EDMA_TCD(IMXRT_DMA4_BASE, 0); + unsigned int i; + + /* The bootloader only needs this focused eDMA4 write to initialize the + * M7 TCM ECC; it does not need to initialize the full NuttX DMA subsystem. + */ + + /* Run eDMA4 from WAKEUP_AXI at SYS_PLL3_OUT / 2 (240 MHz). */ + + if (imxrt_ccm_configure_root_clock(CCM_CR_WAKEUP_AXI, + SYS_PLL3_OUT, 2) < 0 || + imxrt_ccm_gate_on(CCM_LPCG_EDMA4, true) < 0) + { + return -EIO; + } + + for (i = 0; i < sizeof(starts) / sizeof(starts[0]); i++) + { + /* Clear stale DONE and error status. Hardware requests and the error + * interrupt stay disabled; the transfer is started by software and + * completion is polled. + */ + + putreg32(EDMA_CH_CSR_DONE, tcd + IMXRT_EDMA_CH_CSR_OFFSET); + putreg32(EDMA_CH_ES_ERR, tcd + IMXRT_EDMA_CH_ES_OFFSET); + + /* Fill the whole region with 64-bit zero writes. */ + + putreg32((uintptr_t)&g_m7_tcm_fill, + tcd + IMXRT_EDMA_TCD_SADDR_OFFSET); + putreg32(starts[i], tcd + IMXRT_EDMA_TCD_DADDR_OFFSET); + putreg32(ends[i] - starts[i], tcd + IMXRT_EDMA_TCD_NBYTES_OFFSET); + putreg16(EDMA_TCD_ATTR_DSIZE(EDMA_64BIT) | + EDMA_TCD_ATTR_SSIZE(EDMA_64BIT), + tcd + IMXRT_EDMA_TCD_ATTR_OFFSET); + + /* Keep re-reading the same zero source; step the destination by one + * 64-bit write. + */ + + putreg16(0, tcd + IMXRT_EDMA_TCD_SOFF_OFFSET); + putreg16(sizeof(g_m7_tcm_fill), tcd + IMXRT_EDMA_TCD_DOFF_OFFSET); + + /* One major loop iteration; the whole region is in NBYTES. */ + + putreg16(1, tcd + IMXRT_EDMA_TCD_CITER_OFFSET); + putreg16(1, tcd + IMXRT_EDMA_TCD_BITER_OFFSET); + + /* No destination address adjustment or scatter/gather chain. */ + + putreg32(0, tcd + IMXRT_EDMA_TCD_DLAST_SGA_OFFSET); + + /* Launch the transfer by software request. */ + + putreg16(EDMA_TCD_CSR_START | EDMA_TCD_CSR_DREQ, + tcd + IMXRT_EDMA_TCD_CSR_OFFSET); + + /* An error does not set DONE, so poll for both. */ + + while ((getreg32(tcd + IMXRT_EDMA_CH_CSR_OFFSET) & + EDMA_CH_CSR_DONE) == 0) + { + if ((getreg32(tcd + IMXRT_EDMA_CH_ES_OFFSET) & + EDMA_CH_ES_ERR) != 0) + { + /* Clear error and return */ + + putreg32(EDMA_CH_ES_ERR, tcd + IMXRT_EDMA_CH_ES_OFFSET); + return -EIO; + } + } + + putreg32(EDMA_CH_CSR_DONE, tcd + IMXRT_EDMA_CH_CSR_OFFSET); + } + + return 0; +} + /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: imxrt118x_release_cm7 + * Name: imxrt118x_prepare_cm7 ****************************************************************************/ -int imxrt118x_release_cm7(uintptr_t vtor) +int imxrt118x_prepare_cm7(uintptr_t vtor) { uint32_t cfg; int ret; @@ -206,7 +324,8 @@ int imxrt118x_release_cm7(uintptr_t vtor) /* Program the M7 initial VTOR and force its clocks on. */ cfg = getreg32(IMXRT_AON_M7_CFG); - cfg = (cfg & ~AON_M7_CFG_INITVTOR_MASK) | + cfg = (cfg & ~(AON_M7_CFG_TCM_SIZE_MASK | + AON_M7_CFG_INITVTOR_MASK)) | AON_M7_CFG_INITVTOR(vtor >> AON_M7_CFG_INITVTOR_SHIFT) | AON_M7_CFG_HCLK_FORCE_ON | AON_M7_CFG_CORECLK_FORCE_ON; @@ -224,6 +343,21 @@ int imxrt118x_release_cm7(uintptr_t vtor) return ret; } + ret = imxrt118x_initialize_m7_tcm_ecc(); + if (ret < 0) + { + return ret; + } + + return 0; +} + +/**************************************************************************** + * Name: imxrt118x_start_cm7 + ****************************************************************************/ + +int imxrt118x_start_cm7(void) +{ /* Kick the M7 by toggling its clock around WAIT deassertion. */ diff --git a/arch/arm/src/imxrt/imxrt118x_start_cm7.h b/arch/arm/src/imxrt/imxrt118x_start_cm7.h index c5edc4ae369..d945d742642 100644 --- a/arch/arm/src/imxrt/imxrt118x_start_cm7.h +++ b/arch/arm/src/imxrt/imxrt118x_start_cm7.h @@ -35,6 +35,7 @@ * Public Function Prototypes ****************************************************************************/ -int imxrt118x_release_cm7(uintptr_t vtor); +int imxrt118x_prepare_cm7(uintptr_t vtor); +int imxrt118x_start_cm7(void); #endif /* __ARCH_ARM_SRC_IMXRT_IMXRT118X_START_CM7_H */ diff --git a/boards/arm/imxrt/imxrt1180-evk/scripts/flash-m33.ld b/boards/arm/imxrt/imxrt1180-evk/scripts/flash-m33.ld index 26f901bbc83..2863ae11608 100644 --- a/boards/arm/imxrt/imxrt1180-evk/scripts/flash-m33.ld +++ b/boards/arm/imxrt/imxrt1180-evk/scripts/flash-m33.ld @@ -48,6 +48,8 @@ MEMORY flash (rx) : ORIGIN = 0x28000000, LENGTH = 512K /* FlexSPI XIP window reserved for the M33 image */ systcm (rwx): ORIGIN = 0x20000000, LENGTH = 128K /* CM33 private System TCM */ ocram2 (rw) : ORIGIN = 0x20500000, LENGTH = 16K /* OCRAM2 (DMA/TRDC accessible); USB DMA buffers only */ + itcm_m7 (rw): ORIGIN = 0x303c0000, LENGTH = 256K /* M7 ITCM alias, accessible to M33 eDMA */ + dtcm_m7 (rw): ORIGIN = 0x30400000, LENGTH = 256K /* M7 DTCM alias, accessible to M33 eDMA */ } OUTPUT_ARCH(arm) @@ -180,6 +182,11 @@ SECTIONS _boot_loadaddr = ORIGIN(flash); _boot_size = LENGTH(flash); _ram_size = LENGTH(systcm); + + _sitcm_m7 = ORIGIN(itcm_m7); + _eitcm_m7 = ORIGIN(itcm_m7) + LENGTH(itcm_m7); + _sdtcm_m7 = ORIGIN(dtcm_m7); + _edtcm_m7 = ORIGIN(dtcm_m7) + LENGTH(dtcm_m7); } /* The M7 image starts at 0x2808_0000. Fail the link rather than silently diff --git a/boards/arm/imxrt/imxrt1180-evk/src/imxrt_bootloader.c b/boards/arm/imxrt/imxrt1180-evk/src/imxrt_bootloader.c index 6e56f2a3469..1d46c473bea 100644 --- a/boards/arm/imxrt/imxrt1180-evk/src/imxrt_bootloader.c +++ b/boards/arm/imxrt/imxrt1180-evk/src/imxrt_bootloader.c @@ -61,7 +61,12 @@ int bootloader_main(int argc, char *argv[]) up_disable_irq(IMXRT_IRQ_LPUART1); irq_detach(IMXRT_IRQ_LPUART1); - if (imxrt118x_release_cm7(M7_ENTRY) < 0) + if (imxrt118x_prepare_cm7(M7_ENTRY) < 0) + { + return EXIT_FAILURE; + } + + if (imxrt118x_start_cm7() < 0) { return EXIT_FAILURE; }