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; }