diff --git a/soc/arm/st_stm32/stm32h7/CMakeLists.txt b/soc/arm/st_stm32/stm32h7/CMakeLists.txt index 143348b72b5..399a487569c 100644 --- a/soc/arm/st_stm32/stm32h7/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32h7/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources_ifdef(CONFIG_CPU_CORTEX_M7 soc_m7.c) +zephyr_sources_ifdef(CONFIG_CPU_CORTEX_M4 soc_m4.c) diff --git a/soc/arm/st_stm32/stm32h7/Kconfig.series b/soc/arm/st_stm32/stm32h7/Kconfig.series index cddc4d3c45e..da127b92b71 100644 --- a/soc/arm/st_stm32/stm32h7/Kconfig.series +++ b/soc/arm/st_stm32/stm32h7/Kconfig.series @@ -13,5 +13,33 @@ config SOC_SERIES_STM32H7X select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select NEWLIB_LIBC + select USE_STM32_HAL_RCC_EX if CPU_CORTEX_M4 help Enable support for STM32H7 MCU series + +config STM32H7_DUAL_CORE + bool "Enable Dual Core" + depends on SOC_SERIES_STM32H7X + +choice STM32H7_DUAL_CORE_BOOT +prompt "STM32H7x Boot type selection" +depends on STM32H7_DUAL_CORE + +config STM32H7_BOOT_CM4_CM7 + bool "Boot both CM4 and CM7" + help + Cortex-M7 and Cortex-M4 running from the flash (each from a bank) + System configuration performed by the Cortex-M7 + Cortex-M4 goes to STOP after boot, then woken-up by Cortex-M7 using + a HW semaphore + +config STM32H7_BOOT_CM7_CM4GATED + bool "Boot CM7. CM4 boot gated" + help + Cortex-M4 boot is gated using Flash option bytes + Cortex-M7 and Cortex-M4 running from the flash (each from a bank) + Cortex-M7 boots , performs the System configuration then enable the + Cortex-M4 boot using RCC. + This mode requires option byte setting update (BCM4 uncheked) + +endchoice diff --git a/soc/arm/st_stm32/stm32h7/soc.h b/soc/arm/st_stm32/stm32h7/soc.h index 24022ebad98..505c6d1c088 100644 --- a/soc/arm/st_stm32/stm32h7/soc.h +++ b/soc/arm/st_stm32/stm32h7/soc.h @@ -17,6 +17,23 @@ */ #include +#ifdef CONFIG_STM32H7_DUAL_CORE + +#define LL_HSEM_ID_0 (0U) /* HW semaphore 0 */ +#define LL_HSEM_MASK_0 (1 << LL_HSEM_ID_0) + +#include + +#ifdef CONFIG_CPU_CORTEX_M4 + +#include +#include +#include + +#endif /* CONFIG_CPU_CORTEX_M4 */ + +#endif /* CONFIG_STM32H7_DUAL_CORE */ + #ifdef CONFIG_CLOCK_CONTROL_STM32_CUBE #include #include diff --git a/soc/arm/st_stm32/stm32h7/soc_m4.c b/soc/arm/st_stm32/stm32h7/soc_m4.c new file mode 100644 index 00000000000..d1f744af373 --- /dev/null +++ b/soc/arm/st_stm32/stm32h7/soc_m4.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for STM32H7 CM4 processor + */ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_STM32H7_BOOT_CM4_CM7) +void stm32h7_m4_boot_stop(void) +{ + /* + * Domain D2 goes to STOP mode (Cortex-M4 in deep-sleep) waiting for + * Cortex-M7 to perform system initialization (system clock config, + * external memory configuration.. ) + */ + + /* Clear pending events if any */ + __SEV(); + __WFE(); + + /* Select the domain Power Down DeepSleep */ + LL_PWR_SetRegulModeDS(LL_PWR_REGU_DSMODE_MAIN); + /* Keep DSTOP mode when D2 domain enters Deepsleep */ + LL_PWR_CPU_SetD2PowerMode(LL_PWR_CPU_MODE_D2STOP); + LL_PWR_CPU2_SetD2PowerMode(LL_PWR_CPU2_MODE_D2STOP); + /* Set SLEEPDEEP bit of Cortex System Control Register */ + LL_LPM_EnableDeepSleep(); + + /* Ensure that all instructions done before entering STOP mode */ + __DSB(); + __ISB(); + /* Request Wait For Event */ + __WFE(); + + /* Reset SLEEPDEEP bit of Cortex System Control Register, + * the following LL API Clear SLEEPDEEP bit of Cortex + * System Control Register + */ + LL_LPM_EnableSleep(); +} +#endif /* CONFIG_STM32H7_BOOT_CM4_CM7 */ + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + * So the init priority has to be 0 (zero). + * + * @return 0 + */ +static int stm32h7_m4_init(struct device *arg) +{ + u32_t key; + + key = irq_lock(); + + /* Install default handler that simply resets the CPU + * if configured in the kernel, NOP otherwise + */ + NMI_INIT(); + + irq_unlock(key); + + /*HW semaphore Clock enable*/ + LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_HSEM); + +#if defined(CONFIG_STM32H7_BOOT_CM4_CM7) + /* Activate HSEM notification for Cortex-M4*/ + LL_HSEM_EnableIT_C2IER(HSEM, LL_HSEM_MASK_0); + + /* Boot and enter stop mode */ + stm32h7_m4_boot_stop(); + + /* Clear HSEM flag */ + LL_HSEM_ClearFlag_C2ICR(HSEM, LL_HSEM_MASK_0); +#endif /* CONFIG_STM32H7_BOOT_CM4_CM7 */ + + return 0; +} + +SYS_INIT(stm32h7_m4_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/st_stm32/stm32h7/soc_m7.c b/soc/arm/st_stm32/stm32h7/soc_m7.c index 03d70e0953b..4ae3611ee2e 100644 --- a/soc/arm/st_stm32/stm32h7/soc_m7.c +++ b/soc/arm/st_stm32/stm32h7/soc_m7.c @@ -16,6 +16,41 @@ #include #include +#if defined(CONFIG_STM32H7_DUAL_CORE) +static int stm32h7_m4_wakeup(struct device *arg) +{ + + /*HW semaphore Clock enable*/ + LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_HSEM); + + if (IS_ENABLED(CONFIG_STM32H7_BOOT_CM4_CM7)) { + u32_t timeout; + + /* + * When system initialization is finished, Cortex-M7 will + * release Cortex-M4 by means of HSEM notification + */ + + /*Take HSEM */ + LL_HSEM_1StepLock(HSEM, LL_HSEM_ID_0); + /*Release HSEM in order to notify the CPU2(CM4)*/ + LL_HSEM_ReleaseLock(HSEM, LL_HSEM_ID_0, 0); + + /* wait until CPU2 wakes up from stop mode */ + timeout = 0xFFFF; + while ((LL_RCC_D2CK_IsReady() == 0) && ((timeout--) > 0)) { + } + if (timeout < 0) { + return -EIO; + } + } else if (IS_ENABLED(CONFIG_STM32H7_BOOT_CM7_CM4GATED)) { + /* Start CM4 */ + LL_RCC_ForceCM4Boot(); + } + + return 0; +} +#endif /* CONFIG_STM32H7_DUAL_CORE */ /** * @brief Perform basic hardware initialization at boot. @@ -55,3 +90,8 @@ static int stm32h7_init(struct device *arg) SYS_INIT(stm32h7_init, PRE_KERNEL_1, 0); + +#if defined(CONFIG_STM32H7_DUAL_CORE) +/* Unlock M4 once system configuration has been done */ +SYS_INIT(stm32h7_m4_wakeup, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY); +#endif /* CONFIG_STM32H7_DUAL_CORE */