soc: rt11xx: Enabled multicore support with second image

RT11xx features CM4 core, which must be booted from CM7 core. Add
support for loading an image for the CM4 to RAM, and booting the CM4 core
from this image. Each image is built independently using sysbuild, and the
M4 image build produces built collateral with load address information the
M7 image can use to load it to RAM

Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc
index 6ab2aba..4d1f2d7 100644
--- a/soc/arm/nxp_imx/rt/Kconfig.soc
+++ b/soc/arm/nxp_imx/rt/Kconfig.soc
@@ -651,7 +651,7 @@
 
 menuconfig NXP_IMX_RT_BOOT_HEADER
 	bool "Boot header"
-	depends on !BOOTLOADER_MCUBOOT
+	depends on ((!BOOTLOADER_MCUBOOT) && (CODE_FLEXSPI || CODE_FLEXSPI2))
 	help
 	  Enable data structures required by the boot ROM to boot the
 	  application from an external flash device.
@@ -737,5 +737,15 @@
 	  Creates linker section and MPU region for OCRAM region with
 	  noncacheable attribute. OCRAM memory is useful for fast DMA transfers.
 
+config SECOND_CORE_MCUX
+	bool "Dual core operation on the RT11xx series"
+	depends on SOC_SERIES_IMX_RT11XX
+	help
+	  Indicates the second core will be enabled, and the part will run
+	  in dual core mode. Enables dual core operation on the RT11xx series,
+	  by booting an image targeting the Cortex-M4 from the Cortex-M7 CPU.
+	  The M4 image will be loaded from flash into RAM based off a
+	  generated header specifying the VMA and LMA of each memory section
+	  to load
 
 endif # SOC_SERIES_IMX_RT
diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c
index 2fd7bf6..edad42e 100644
--- a/soc/arm/nxp_imx/rt/soc_rt11xx.c
+++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c
@@ -20,6 +20,17 @@
 #include <fsl_flexspi_nor_boot.h>
 #endif
 #include <zephyr/dt-bindings/clock/imx_ccm_rev2.h>
+#if  defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M7)
+#include <zephyr_image_info.h>
+/* Memcpy macro to copy segments from secondary core image stored in flash
+ * to RAM section that secondary core boots from.
+ * n is the segment number, as defined in zephyr_image_info.h
+ */
+#define MEMCPY_SEGMENT(n, _)							\
+	memcpy((uint32_t *)((SEGMENT_LMA_ADDRESS_ ## n) - ADJUSTED_LMA),	\
+		(uint32_t *)(SEGMENT_LMA_ADDRESS_ ## n),			\
+		(SEGMENT_SIZE_ ## n))
+#endif
 #if CONFIG_USB_DC_NXP_EHCI
 #include "usb_phy.h"
 #include "usb.h"
@@ -596,6 +607,7 @@
  *
  * Initialize the interrupt controller device drivers.
  * Also initialize the timer device driver, if required.
+ * If dual core operation is enabled, the second core image will be loaded to RAM
  *
  * @return 0
  */
@@ -614,6 +626,24 @@
 		SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
 	}
 
+#if  defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M7)
+	/**
+	 * Copy CM4 core from flash to memory. Note that depending on where the
+	 * user decided to store CM4 code, this is likely going to read from the
+	 * flexspi while using XIP. Provided we DO NOT WRITE TO THE FLEXSPI,
+	 * this operation is safe.
+	 *
+	 * Note that this copy MUST occur before enabling the M7 caching to
+	 * ensure the data is written directly to RAM (since the M4 core will use it)
+	 */
+	LISTIFY(SEGMENT_NUM, MEMCPY_SEGMENT, (;));
+	/* Set the boot address for the second core */
+	uint32_t boot_address = (uint32_t)(DT_REG_ADDR(DT_CHOSEN(zephyr_cpu1_region)));
+	/* Set VTOR for the CM4 core */
+	IOMUXC_LPSR_GPR->GPR0 = IOMUXC_LPSR_GPR_GPR0_CM4_INIT_VTOR_LOW(boot_address >> 3u);
+	IOMUXC_LPSR_GPR->GPR1 = IOMUXC_LPSR_GPR_GPR1_CM4_INIT_VTOR_HIGH(boot_address >> 16u);
+#endif
+
 #if defined(CONFIG_SOC_MIMXRT1176_CM7) || defined(CONFIG_SOC_MIMXRT1166_CM7)
 	if (SCB_CCR_IC_Msk != (SCB_CCR_IC_Msk & SCB->CCR)) {
 		SCB_EnableICache();
@@ -687,3 +717,24 @@
 #endif
 
 SYS_INIT(imxrt_init, PRE_KERNEL_1, 0);
+
+#if  defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M7)
+/**
+ * @brief Kickoff secondary core.
+ *
+ * Kick the secondary core out of reset. The
+ * core image was already copied to RAM (and the boot address was set) in
+ * imxrt_init()
+ *
+ * @return 0
+ */
+static int second_core_boot(const struct device *arg)
+{
+	/* Kick CM4 core out of reset */
+	SRC->CTRL_M4CORE = SRC_CTRL_M4CORE_SW_RESET_MASK;
+	SRC->SCR |= SRC_SCR_BT_RELEASE_M4_MASK;
+	return 0;
+}
+
+SYS_INIT(second_core_boot, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
+#endif