From 2e426a8571130ea486641af21893fb8685d91e98 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Thu, 20 Mar 2025 11:13:46 +0100 Subject: [PATCH 01/11] west.yml: Update west.yml for stm32mp13 hal Update west.yml for STM32MP13 HAL Signed-off-by: Julien Racki --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4f7196d7f48df..ab8abfeaceb08 100644 --- a/west.yml +++ b/west.yml @@ -238,7 +238,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 4ec1fd2e65b4f55eb516b16df73a2dd9f0cf6e1f + revision: def7e1a025877a35d070439e70668f5ec319c32e path: modules/hal/stm32 groups: - hal From fdf755ac813b76b7518f64384fc8ca86544ea384 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 10:17:52 +0100 Subject: [PATCH 02/11] arch: arm: Add Cortex-A7 support Pass the correct -mfpu and -mcpu flags to the compiler when building for the Cortex-A7. Signed-off-by: Julien Racki --- arch/arm/core/cortex_a_r/Kconfig | 9 +++++++++ cmake/compiler/iar/iccarm-cpu.cmake | 2 ++ cmake/gcc-m-cpu.cmake | 2 ++ cmake/gcc-m-fpu.cmake | 4 ++++ .../mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h | 2 ++ 5 files changed, 19 insertions(+) diff --git a/arch/arm/core/cortex_a_r/Kconfig b/arch/arm/core/cortex_a_r/Kconfig index ddf388c195b6c..a6176bbe5c094 100644 --- a/arch/arm/core/cortex_a_r/Kconfig +++ b/arch/arm/core/cortex_a_r/Kconfig @@ -13,6 +13,15 @@ # CPU_AARCH32_CORTEX_A / if CPU_AARCH32_CORTEX_R blocks so they are not # exposed if one selects a different ARM Cortex Family (Cortex-M). +config CPU_CORTEX_A7 + bool + select CPU_AARCH32_CORTEX_A + select ARMV7_A + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE + help + This option signifies the use of a Cortex-A7 CPU. + config CPU_CORTEX_A9 bool select CPU_AARCH32_CORTEX_A diff --git a/cmake/compiler/iar/iccarm-cpu.cmake b/cmake/compiler/iar/iccarm-cpu.cmake index 70eee9240b654..f191bb7e314a8 100644 --- a/cmake/compiler/iar/iccarm-cpu.cmake +++ b/cmake/compiler/iar/iccarm-cpu.cmake @@ -67,6 +67,8 @@ if("${ARCH}" STREQUAL "arm") set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) endif() endif() + elseif(CONFIG_CPU_CORTEX_A7) + set(ICCARM_CPU Cortex-A7) elseif(CONFIG_CPU_CORTEX_A9) set(ICCARM_CPU Cortex-A9) else() diff --git a/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index 6f00283b6b8e4..75b13fa423844 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -84,6 +84,8 @@ if("${ARCH}" STREQUAL "arm") set(GCC_M_CPU ${GCC_M_CPU}+nofp.dp) endif() endif() + elseif(CONFIG_CPU_CORTEX_A7) + set(GCC_M_CPU cortex-a7) elseif(CONFIG_CPU_CORTEX_A9) set(GCC_M_CPU cortex-a9) else() diff --git a/cmake/gcc-m-fpu.cmake b/cmake/gcc-m-fpu.cmake index d1ce9655b46d0..aafe5b75c8616 100644 --- a/cmake/gcc-m-fpu.cmake +++ b/cmake/gcc-m-fpu.cmake @@ -45,6 +45,10 @@ if("${ARCH}" STREQUAL "arm") set(FPU_FOR_cortex-m85+nodsp auto) set(GCC_M_FPU ${FPU_FOR_${GCC_M_CPU}}) + elseif(CONFIG_CPU_AARCH32_CORTEX_A) + if(CONFIG_CPU_CORTEX_A7) + set(GCC_M_FPU vfpv4-d16) + endif() endif() endif() diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h index 71dfda7c19311..21f9f272a6337 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h @@ -103,6 +103,8 @@ extern "C" { #else #define PROCESSOR_NAME "cortex-r52" #endif +#elif defined(CONFIG_CPU_CORTEX_A7) +#define PROCESSOR_NAME "cortex-a7" #elif defined(CONFIG_CPU_CORTEX_A9) #define PROCESSOR_NAME "cortex-a9" #endif From f9a3196b40d852564706d70cd6792240b19aeea4 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 16:12:36 +0100 Subject: [PATCH 03/11] arch: arm: Use the armv8_timer.h for the Cortex A7 We can't use the timer.h as the arm timer is within the soc and does not have an address. Instead we use the armv8_timer.h, renaming it to armv7_v8_timer.h for the Cortex-A7 as the cp15 access are compatible. Signed-off-by: Julien Racki --- include/zephyr/arch/arm/arch.h | 4 ++-- .../arch/arm/cortex_a_r/{armv8_timer.h => armv7_v8_timer.h} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename include/zephyr/arch/arm/cortex_a_r/{armv8_timer.h => armv7_v8_timer.h} (86%) diff --git a/include/zephyr/arch/arm/arch.h b/include/zephyr/arch/arm/arch.h index 9bbcc2375f1cd..aa8042644a1e4 100644 --- a/include/zephyr/arch/arm/arch.h +++ b/include/zephyr/arch/arm/arch.h @@ -40,9 +40,9 @@ #elif defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include #include -#if defined(CONFIG_AARCH32_ARMV8_R) +#if defined(CONFIG_AARCH32_ARMV8_R) || defined(CONFIG_CPU_CORTEX_A7) #include -#include +#include #else #include #endif diff --git a/include/zephyr/arch/arm/cortex_a_r/armv8_timer.h b/include/zephyr/arch/arm/cortex_a_r/armv7_v8_timer.h similarity index 86% rename from include/zephyr/arch/arm/cortex_a_r/armv8_timer.h rename to include/zephyr/arch/arm/cortex_a_r/armv7_v8_timer.h index 3950397f71a62..911bed910f0db 100644 --- a/include/zephyr/arch/arm/cortex_a_r/armv8_timer.h +++ b/include/zephyr/arch/arm/cortex_a_r/armv7_v8_timer.h @@ -5,8 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_ARMV8_TIMER_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_ARMV8_TIMER_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_ARMV7_V8_TIMER_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_ARMV7_V8_TIMER_H_ #ifndef _ASMLANGUAGE @@ -71,4 +71,4 @@ static ALWAYS_INLINE uint64_t arm_arch_timer_count(void) #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_ARMV8_TIMER_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_ARMV7_V8_TIMER_H_ */ From e4a6d29c3b3efb11596f15a0ca28a1840a09a284 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 16:43:18 +0100 Subject: [PATCH 04/11] arch: arm: Adding fault description for the cortex A7 Add support for processing the Fault Status Registers and recoverable data abort for the cortex A7. Based on Cortex-A7 MPCore Technical Reference Manual (ARM DDI 0406). (see https://developer.arm.com/documentation/ddi0406) Signed-off-by: Julien Racki --- arch/arm/core/cortex_a_r/fault.c | 53 ++++++++++++++++++++++++++++++ include/zephyr/arch/arm/arch.h | 14 +++++++- modules/cmsis/cmsis_core_a_r_ext.h | 27 +++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/arch/arm/core/cortex_a_r/fault.c b/arch/arm/core/cortex_a_r/fault.c index daf1d2345ca06..eac07cbf9b25b 100644 --- a/arch/arm/core/cortex_a_r/fault.c +++ b/arch/arm/core/cortex_a_r/fault.c @@ -100,6 +100,59 @@ static uint32_t dump_fault(uint32_t status, uint32_t addr) reason = K_ERR_ARM_UNSUPPORTED_EXCLUSIVE_ACCESS_FAULT; LOG_ERR("Unsupported Exclusive Access Fault @ 0x%08x", addr); break; +#elif defined(CONFIG_ARMV7_A) + case FSR_FS_PERMISSION_FAULT_2ND_LEVEL: + reason = K_ERR_ARM_PERMISSION_FAULT_2ND_LEVEL; + LOG_ERR("2nd Level Permission Fault @ 0x%08x", addr); + break; + case FSR_FS_ACCESS_FLAG_FAULT_1ST_LEVEL: + reason = K_ERR_ARM_ACCESS_FLAG_FAULT_1ST_LEVEL; + LOG_ERR("1st Level Access Flag Fault @ 0x%08x", addr); + break; + case FSR_FS_ACCESS_FLAG_FAULT_2ND_LEVEL: + reason = K_ERR_ARM_ACCESS_FLAG_FAULT_2ND_LEVEL; + LOG_ERR("2nd Level Access Flag Fault @ 0x%08x", addr); + break; + case FSR_FS_CACHE_MAINTENANCE_INSTRUCTION_FAULT: + reason = K_ERR_ARM_CACHE_MAINTENANCE_INSTRUCTION_FAULT; + LOG_ERR("Cache Maintenance Instruction Fault @ 0x%08x", addr); + break; + case FSR_FS_TRANSLATION_FAULT: + reason = K_ERR_ARM_TRANSLATION_FAULT; + LOG_ERR("1st Level Translation Fault @ 0x%08x", addr); + break; + case FSR_FS_TRANSLATION_FAULT_2ND_LEVEL: + reason = K_ERR_ARM_TRANSLATION_FAULT_2ND_LEVEL; + LOG_ERR("2nd Level Translation Fault @ 0x%08x", addr); + break; + case FSR_FS_DOMAIN_FAULT_1ST_LEVEL: + reason = K_ERR_ARM_DOMAIN_FAULT_1ST_LEVEL; + LOG_ERR("1st Level Domain Fault @ 0x%08x", addr); + break; + case FSR_FS_DOMAIN_FAULT_2ND_LEVEL: + reason = K_ERR_ARM_DOMAIN_FAULT_2ND_LEVEL; + LOG_ERR("2nd Level Domain Fault @ 0x%08x", addr); + break; + case FSR_FS_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_1ST_LEVEL: + reason = K_ERR_ARM_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_1ST_LEVEL; + LOG_ERR("1st Level Synchronous External Abort Translation Table @ 0x%08x", addr); + break; + case FSR_FS_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_2ND_LEVEL: + reason = K_ERR_ARM_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_2ND_LEVEL; + LOG_ERR("2nd Level Synchronous External Abort Translation Table @ 0x%08x", addr); + break; + case FSR_FS_TLB_CONFLICT_FAULT: + reason = K_ERR_ARM_TLB_CONFLICT_FAULT; + LOG_ERR("Table Conflict Fault @ 0x%08x", addr); + break; + case FSR_FS_SYNC_PARITY_ERROR_TRANSLATION_TABLE_1ST_LEVEL: + reason = K_ERR_ARM_SYNC_PARITY_ERROR_TRANSLATION_TABLE_1ST_LEVEL; + LOG_ERR("1st Level Synchronous Parity Error Translation Table @ 0x%08x", addr); + break; + case FSR_FS_SYNC_PARITY_ERROR_TRANSLATION_TABLE_2ND_LEVEL: + reason = K_ERR_ARM_SYNC_PARITY_ERROR_TRANSLATION_TABLE_2ND_LEVEL; + LOG_ERR("2nd Level Synchronous Parity Error Translation Table @ 0x%08x", addr); + break; #else case FSR_FS_BACKGROUND_FAULT: reason = K_ERR_ARM_BACKGROUND_FAULT; diff --git a/include/zephyr/arch/arm/arch.h b/include/zephyr/arch/arm/arch.h index aa8042644a1e4..1a33196b15e4f 100644 --- a/include/zephyr/arch/arm/arch.h +++ b/include/zephyr/arch/arm/arch.h @@ -99,13 +99,25 @@ enum k_fatal_error_reason_arch { K_ERR_ARM_ALIGNMENT_FAULT, K_ERR_ARM_BACKGROUND_FAULT, K_ERR_ARM_PERMISSION_FAULT, + K_ERR_ARM_PERMISSION_FAULT_2ND_LEVEL, K_ERR_ARM_SYNC_EXTERNAL_ABORT, K_ERR_ARM_ASYNC_EXTERNAL_ABORT, K_ERR_ARM_SYNC_PARITY_ERROR, K_ERR_ARM_ASYNC_PARITY_ERROR, K_ERR_ARM_DEBUG_EVENT, K_ERR_ARM_TRANSLATION_FAULT, - K_ERR_ARM_UNSUPPORTED_EXCLUSIVE_ACCESS_FAULT + K_ERR_ARM_TRANSLATION_FAULT_2ND_LEVEL, + K_ERR_ARM_UNSUPPORTED_EXCLUSIVE_ACCESS_FAULT, + K_ERR_ARM_ACCESS_FLAG_FAULT_1ST_LEVEL, + K_ERR_ARM_ACCESS_FLAG_FAULT_2ND_LEVEL, + K_ERR_ARM_CACHE_MAINTENANCE_INSTRUCTION_FAULT, + K_ERR_ARM_DOMAIN_FAULT_1ST_LEVEL, + K_ERR_ARM_DOMAIN_FAULT_2ND_LEVEL, + K_ERR_ARM_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_1ST_LEVEL, + K_ERR_ARM_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_2ND_LEVEL, + K_ERR_ARM_TLB_CONFLICT_FAULT, + K_ERR_ARM_SYNC_PARITY_ERROR_TRANSLATION_TABLE_1ST_LEVEL, + K_ERR_ARM_SYNC_PARITY_ERROR_TRANSLATION_TABLE_2ND_LEVEL, }; #endif /* _ASMLANGUAGE */ diff --git a/modules/cmsis/cmsis_core_a_r_ext.h b/modules/cmsis/cmsis_core_a_r_ext.h index 0752b1474fa2b..e1ddce4c0664c 100644 --- a/modules/cmsis/cmsis_core_a_r_ext.h +++ b/modules/cmsis/cmsis_core_a_r_ext.h @@ -29,6 +29,33 @@ #define FSR_FS_ALIGNMENT_FAULT (33) #define FSR_FS_DEBUG_EVENT (34) #define FSR_FS_UNSUPPORTED_EXCLUSIVE_ACCESS_FAULT (53) +#elif defined(CONFIG_ARMV7_A) + +/** + * N.B.: these FSR encodings are only valid when the + * Short-descriptor translation table format is used + */ + +#define FSR_FS_ALIGNMENT_FAULT (1) +#define FSR_FS_DEBUG_EVENT (2) +#define FSR_FS_ACCESS_FLAG_FAULT_1ST_LEVEL (3) +#define FSR_FS_CACHE_MAINTENANCE_INSTRUCTION_FAULT (4) +#define FSR_FS_TRANSLATION_FAULT (5) +#define FSR_FS_ACCESS_FLAG_FAULT_2ND_LEVEL (6) +#define FSR_FS_TRANSLATION_FAULT_2ND_LEVEL (7) +#define FSR_FS_SYNC_EXTERNAL_ABORT (8) +#define FSR_FS_DOMAIN_FAULT_1ST_LEVEL (9) +#define FSR_FS_DOMAIN_FAULT_2ND_LEVEL (11) +#define FSR_FS_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_1ST_LEVEL (12) +#define FSR_FS_PERMISSION_FAULT (13) +#define FSR_FS_SYNC_EXTERNAL_ABORT_TRANSLATION_TABLE_2ND_LEVEL (14) +#define FSR_FS_PERMISSION_FAULT_2ND_LEVEL (15) +#define FSR_FS_TLB_CONFLICT_FAULT (16) +#define FSR_FS_ASYNC_EXTERNAL_ABORT (22) +#define FSR_FS_ASYNC_PARITY_ERROR (24) +#define FSR_FS_SYNC_PARITY_ERROR (25) +#define FSR_FS_SYNC_PARITY_ERROR_TRANSLATION_TABLE_1ST_LEVEL (28) +#define FSR_FS_SYNC_PARITY_ERROR_TRANSLATION_TABLE_2ND_LEVEL (30) #else #define FSR_FS_BACKGROUND_FAULT (0) #define FSR_FS_ALIGNMENT_FAULT (1) From 13ca97d99a2c97295c430e8e7f5ec3e8f713dc38 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 16:53:36 +0100 Subject: [PATCH 05/11] soc: st: stm32: Provide basic support for STM32MP13 series Enable basic support to STM32MP13, in single core configuration (A7) with I and D cache enabled. Signed-off-by: Julien Racki --- soc/st/stm32/common/soc_config.c | 4 + soc/st/stm32/soc.yml | 3 + soc/st/stm32/stm32mp13x/CMakeLists.txt | 12 +++ soc/st/stm32/stm32mp13x/Kconfig | 14 ++++ soc/st/stm32/stm32mp13x/Kconfig.defconfig | 20 +++++ .../stm32mp13x/Kconfig.defconfig.stm32mp13_a7 | 11 +++ soc/st/stm32/stm32mp13x/Kconfig.soc | 18 +++++ soc/st/stm32/stm32mp13x/soc.c | 80 +++++++++++++++++++ soc/st/stm32/stm32mp13x/soc.h | 16 ++++ 9 files changed, 178 insertions(+) create mode 100644 soc/st/stm32/stm32mp13x/CMakeLists.txt create mode 100644 soc/st/stm32/stm32mp13x/Kconfig create mode 100644 soc/st/stm32/stm32mp13x/Kconfig.defconfig create mode 100644 soc/st/stm32/stm32mp13x/Kconfig.defconfig.stm32mp13_a7 create mode 100644 soc/st/stm32/stm32mp13x/Kconfig.soc create mode 100644 soc/st/stm32/stm32mp13x/soc.c create mode 100644 soc/st/stm32/stm32mp13x/soc.h diff --git a/soc/st/stm32/common/soc_config.c b/soc/st/stm32/common/soc_config.c index 9275ce72babba..07eb74a697c65 100644 --- a/soc/st/stm32/common/soc_config.c +++ b/soc/st/stm32/common/soc_config.c @@ -76,6 +76,8 @@ static int st_stm32_common_config(void) LL_DBGMCU_EnableDebugInStopMode(); #elif defined(CONFIG_SOC_SERIES_STM32WB0X) LL_PWR_EnableDEEPSTOP2(); +#elif defined(CONFIG_SOC_SERIES_STM32MP13X) + LL_DBGMCU_EnableDebugInLowPowerMode(); #else /* all other parts */ LL_DBGMCU_EnableDBGStopMode(); #endif @@ -90,6 +92,8 @@ static int st_stm32_common_config(void) LL_DBGMCU_DisableDebugInStopMode(); #elif defined(CONFIG_SOC_SERIES_STM32WB0X) LL_PWR_DisableDEEPSTOP2(); +#elif defined(CONFIG_SOC_SERIES_STM32MP13X) + LL_DBGMCU_DisableDebugInLowPowerMode(); #else /* all other parts */ LL_DBGMCU_DisableDBGStopMode(); #endif diff --git a/soc/st/stm32/soc.yml b/soc/st/stm32/soc.yml index 21b92d9eea44b..a12213170958c 100644 --- a/soc/st/stm32/soc.yml +++ b/soc/st/stm32/soc.yml @@ -187,6 +187,9 @@ family: - name: stm32mp1x socs: - name: stm32mp157cxx + - name: stm32mp13x + socs: + - name: stm32mp135fxx - name: stm32n6x socs: - name: stm32n657xx diff --git a/soc/st/stm32/stm32mp13x/CMakeLists.txt b/soc/st/stm32/stm32mp13x/CMakeLists.txt new file mode 100644 index 0000000000000..792d64f8df5ca --- /dev/null +++ b/soc/st/stm32/stm32mp13x/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2025 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(${ZEPHYR_BASE}/drivers) +zephyr_sources( + soc.c + ) + +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/st/stm32/stm32mp13x/Kconfig b/soc/st/stm32/stm32mp13x/Kconfig new file mode 100644 index 0000000000000..7be5ca01a0c1e --- /dev/null +++ b/soc/st/stm32/stm32mp13x/Kconfig @@ -0,0 +1,14 @@ +# STMicroelectronics STM32MP13 MPU series + +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_STM32MP13X + select ARM + select CPU_CORTEX_A7 + select HAS_STM32CUBE + select CPU_HAS_FPU + select SOC_EARLY_INIT_HOOK + select ARM_ARCH_TIMER + select SYS_CLOCK_EXISTS + select XIP diff --git a/soc/st/stm32/stm32mp13x/Kconfig.defconfig b/soc/st/stm32/stm32mp13x/Kconfig.defconfig new file mode 100644 index 0000000000000..2a3929e30a7ba --- /dev/null +++ b/soc/st/stm32/stm32mp13x/Kconfig.defconfig @@ -0,0 +1,20 @@ +# STMicroelectronics STM32MP13 MPU series + +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_STM32MP13X + +rsource "Kconfig.defconfig.stm32mp13_a7" + +config CACHE_MANAGEMENT + default y + +DT_STM32_CPU_CLOCK_PATH := $(dt_nodelabel_path,cpusw) +DT_STM32_CPU_CLOCK_FREQ := $(dt_node_int_prop_int,$(DT_STM32_CPU_CLOCK_PATH),clock-frequency) + +# For STM32MP13, override the default value defined in STM32 Kconfig +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(DT_STM32_CPU_CLOCK_FREQ) if $(dt_nodelabel_enabled,cpusw) + +endif # SOC_SERIES_STM32MP13X diff --git a/soc/st/stm32/stm32mp13x/Kconfig.defconfig.stm32mp13_a7 b/soc/st/stm32/stm32mp13x/Kconfig.defconfig.stm32mp13_a7 new file mode 100644 index 0000000000000..f65e137dab620 --- /dev/null +++ b/soc/st/stm32/stm32mp13x/Kconfig.defconfig.stm32mp13_a7 @@ -0,0 +1,11 @@ +# STMicroelectronics STM32MP13_A7 MPU + +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32MP135FXX + +config NUM_IRQS + default 181 + +endif # SOC_STM32MP135FXX diff --git a/soc/st/stm32/stm32mp13x/Kconfig.soc b/soc/st/stm32/stm32mp13x/Kconfig.soc new file mode 100644 index 0000000000000..9507ce31a9be8 --- /dev/null +++ b/soc/st/stm32/stm32mp13x/Kconfig.soc @@ -0,0 +1,18 @@ +# STMicroelectronics STM32MP13 MPU series + +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_STM32MP13X + bool + select SOC_FAMILY_STM32 + +config SOC_SERIES + default "stm32mp13x" if SOC_SERIES_STM32MP13X + +config SOC_STM32MP135FXX + bool + select SOC_SERIES_STM32MP13X + +config SOC + default "stm32mp135fxx" if SOC_STM32MP135FXX diff --git a/soc/st/stm32/stm32mp13x/soc.c b/soc/st/stm32/stm32mp13x/soc.c new file mode 100644 index 0000000000000..7d07902637319 --- /dev/null +++ b/soc/st/stm32/stm32mp13x/soc.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for STM32MP13 processor + */ + +#include +#include +#include +#include + +#include +#include + +#define VECTOR_ADDRESS ((uintptr_t)_vector_start) + +void relocate_vector_table(void) +{ + write_sctlr(read_sctlr() & ~HIVECS); + write_vbar(VECTOR_ADDRESS & VBAR_MASK); + barrier_isync_fence_full(); +} + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + */ + +void soc_early_init_hook(void) +{ + /* Update CMSIS SystemCoreClock variable (HCLK) */ + SystemCoreClock = 1000000000U; + + /* Clear TE bit to take exceptions in Thumb mode to fix the DDR init */ + write_sctlr(read_sctlr() & ~SCTLR_TE_Msk); + barrier_isync_fence_full(); +} + +static const struct arm_mmu_region mmu_regions[] = { + MMU_REGION_FLAT_ENTRY("APB1", 0x40000000, 0x19400, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("APB2", 0x44000000, 0x14000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("AHB2", 0x48000000, 0x1040000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("APB6", 0x4C000000, 0xC400, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("AHB4", 0x50000000, 0xD400, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("APB3", 0x50020000, 0xA400, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("DEBUG APB", 0x50080000, 0x5D000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("AHB5", 0x54000000, 0x8000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("AXIMC", 0x57000000, 0x100000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("AHB6", 0x58000000, 0x10000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("APB4", 0x5A000000, 0x7400, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("APB5", 0x5C000000, 0xA400, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("GIC", 0xA0021000, 0x7000, MPERM_R | MPERM_W | MT_DEVICE), + + MMU_REGION_FLAT_ENTRY("vectors", 0xC0000000, 0x1000, MPERM_R | MPERM_X | MT_NORMAL), + + MMU_REGION_FLAT_ENTRY("DAPBUS", 0xE0080000, 0x5D000, MPERM_R | MPERM_W | MT_DEVICE), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; diff --git a/soc/st/stm32/stm32mp13x/soc.h b/soc/st/stm32/stm32mp13x/soc.h new file mode 100644 index 0000000000000..49847550700e1 --- /dev/null +++ b/soc/st/stm32/stm32mp13x/soc.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _STM32MP13SOC_H_ +#define _STM32MP13SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#endif /* !_ASMLANGUAGE */ + +#endif /* _STM32MP13SOC_H_ */ From eb33cacc6bfd1ddad2c655cc4b4f65e4d24ff30f Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 17:38:10 +0100 Subject: [PATCH 06/11] include: dt-bindings: reset: Add stm32mp13 reset Add STM32MP13 dt bindings for reset Signed-off-by: Julien Racki --- .../dt-bindings/reset/stm32mp13_reset.h | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 include/zephyr/dt-bindings/reset/stm32mp13_reset.h diff --git a/include/zephyr/dt-bindings/reset/stm32mp13_reset.h b/include/zephyr/dt-bindings/reset/stm32mp13_reset.h new file mode 100644 index 0000000000000..f393fdb269015 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/stm32mp13_reset.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_STM32MP13_RESET_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_STM32MP13_RESET_H_ + +/** + * Pack RCC register offset and bit in one 32-bit value. + * + * bits[4..0] stores the reset controller bit in 32bit RCC register + * bits[16..5] stores the reset controller set register offset from RCC base + * bits[28..17] stores the reset controller clear register offset from RCC base + * + * @param bus STM32 bus name + * @param bit Reset bit + */ +#define STM32_RESET(bus, bit) \ + (((STM32_RESET_BUS_##bus##_CLR) << 17U) | ((STM32_RESET_BUS_##bus##_SET) << 5U) | (bit)) + +/* RCC bus reset register offset */ +#define STM32_RESET_BUS_AHB2_SET 0x6D0 +#define STM32_RESET_BUS_AHB2_CLR 0x6D4 +#define STM32_RESET_BUS_AHB4_SET 0x6E0 +#define STM32_RESET_BUS_AHB4_CLR 0x6E4 +#define STM32_RESET_BUS_AHB5_SET 0x6E8 +#define STM32_RESET_BUS_AHB5_CLR 0x6EC +#define STM32_RESET_BUS_AHB6_SET 0x6F0 +#define STM32_RESET_BUS_AHB6_CLR 0x6F4 +#define STM32_RESET_BUS_APB1_SET 0x6A0 +#define STM32_RESET_BUS_APB1_CLR 0x6A4 +#define STM32_RESET_BUS_APB2_SET 0x6A8 +#define STM32_RESET_BUS_APB2_CLR 0x6AC +#define STM32_RESET_BUS_APB3_SET 0x6B0 +#define STM32_RESET_BUS_APB3_CLR 0x6B4 +#define STM32_RESET_BUS_APB4_SET 0x6B8 +#define STM32_RESET_BUS_APB4_CLR 0x6BC +#define STM32_RESET_BUS_APB5_SET 0x6C0 +#define STM32_RESET_BUS_APB5_CLR 0x6C4 +#define STM32_RESET_BUS_APB6_SET 0x6C8 +#define STM32_RESET_BUS_APB6_CLR 0x6CC + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_RESET_STM32MP13_RESET_H_ */ From f860f69654aa4d25a05221ac90ffca98ae2717e4 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 17:40:24 +0100 Subject: [PATCH 07/11] include: dt-bindings: clock: Add stm32mp13 clock Add STM32MP13 dt bindings for the clock definition Signed-off-by: Julien Racki --- .../dt-bindings/clock/stm32mp13_clock.h | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 include/zephyr/dt-bindings/clock/stm32mp13_clock.h diff --git a/include/zephyr/dt-bindings/clock/stm32mp13_clock.h b/include/zephyr/dt-bindings/clock/stm32mp13_clock.h new file mode 100644 index 0000000000000..daf2d8ca2cd57 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/stm32mp13_clock.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32MP13_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32MP13_CLOCK_H_ + +#include "stm32_common_clocks.h" + +/** Bus clocks */ +#define STM32_CLOCK_BUS_APB1 0x700 +#define STM32_CLOCK_BUS_APB2 0x708 +#define STM32_CLOCK_BUS_APB3 0x710 +#define STM32_CLOCK_BUS_APB4 0x728 +#define STM32_CLOCK_BUS_APB5 0x740 +#define STM32_CLOCK_BUS_APB6 0x748 +#define STM32_CLOCK_BUS_AHB2 0x750 +#define STM32_CLOCK_BUS_AHB4 0x768 +#define STM32_CLOCK_BUS_AHB5 0x778 +#define STM32_CLOCK_BUS_AHB6 0x780 + +#define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_APB1 +#define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_AHB6 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32MP13_CLOCK_H_ */ From d10633a3ec817a0ee7bafbec3d40ce898c2b4ee4 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Fri, 21 Mar 2025 17:41:04 +0100 Subject: [PATCH 08/11] dts: bindings: clock: Add stm32mp13 rcc clocks Add STM32MP13 RCC clock bindings Signed-off-by: Julien Racki --- .../clock/st,stm32mp13-cpu-clock-mux.yaml | 31 +++++++++ .../clock/st,stm32mp13-pll-clock.yaml | 68 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 dts/bindings/clock/st,stm32mp13-cpu-clock-mux.yaml create mode 100644 dts/bindings/clock/st,stm32mp13-pll-clock.yaml diff --git a/dts/bindings/clock/st,stm32mp13-cpu-clock-mux.yaml b/dts/bindings/clock/st,stm32mp13-cpu-clock-mux.yaml new file mode 100644 index 0000000000000..529d9ef82599a --- /dev/null +++ b/dts/bindings/clock/st,stm32mp13-cpu-clock-mux.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2025, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32MP13 CPU Clock + Describes the STM32MP13 CPU armv7 timer multiplexer. + For the STM32MP13 the CPU armv7 timer input can either be the HSI or the HSE. + For instance: + cpusw: cpusw { + #clock-cells = <0>; + clocks = <&clk_hsi>; + clock-frequency = ; + compatible = "st,stm32mp13-cpu-clock-mux", "st,stm32-clock-mux"; + status = "okay"; + }; + +compatible: "st,stm32mp13-cpu-clock-mux" + +include: + - name: base.yaml + property-allowlist: + - status + - compatible + - clocks + +properties: + clock-frequency: + required: true + type: int + description: | + default frequency in Hz for the timer diff --git a/dts/bindings/clock/st,stm32mp13-pll-clock.yaml b/dts/bindings/clock/st,stm32mp13-pll-clock.yaml new file mode 100644 index 0000000000000..5128ea05f0d8e --- /dev/null +++ b/dts/bindings/clock/st,stm32mp13-pll-clock.yaml @@ -0,0 +1,68 @@ +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + PLL node binding for STM32MP13 devices + + It can be used to describe 4 different PLLs: PLL1, PLL2, PLL3 and PLL4. + + These PLLs can take one of hse_ck, hsi_ck or csi_ck as input clock. + PLLM factor is used to set the input clock in this acceptable range. + + Each PLL has one output clock whose frequency can be computed with the + following formula: + + f(PLL_P) = f(VCO clock) / (DIVP × DIVR × DIVQ) + + with f(VCO clock) = f(PLL clock input) × 2 × (((DIVN + 1) + (FRACV / 8192)) / DIVM1) + + Note: To reduce the power consumption, it is recommended to configure the VCOx + clock output to the lowest frequency. + + The PLL1 output frequency must not exceed 2000 MHz. + The PLL2 output frequency must not exceed 1600 MHz. + The PLL3 output frequency must not exceed 800 MHz. + The PLL4 output frequency must not exceed 800 MHz. + + Note: The CPU clock should not exceed 1Ghz so avoid configuring the PLL1 to more + than 1000 MHz or program the mpuss_ck mux to use the MPUDIV + (refer to the stm32mp13 reference manual for details) + +compatible: "st,stm32mp13-pll-clock" + +include: [clock-controller.yaml, base.yaml] + +properties: + + "#clock-cells": + const: 0 + + clocks: + required: true + + div-m: + type: int + required: true + description: | + Prescaler for PLLx + input clock + Valid range: 1 - 64 + + mul-n: + type: int + required: true + description: | + PLLx multiplication factor for VCO + Valid range: 31 - 125 + + div-p: + type: int + description: | + PLLx DIVP division factor + Valid range: 1 - 128 + + frac-v: + type: int + description: | + PLLx FRACV fractional latch + Valid range: 1 - 8192 From ac3d4a29ad222579e032e5107daf0b719f2edec9 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Mon, 24 Mar 2025 09:29:21 +0100 Subject: [PATCH 09/11] drivers: clock: Add stm32mp13 clock Add STM32MP13 clock driver. Supported clocks are HSE, HSI, PLL1 and peripheral clock. Signed-off-by: Julien Racki Co-authored-by: Arif Balik --- drivers/clock_control/CMakeLists.txt | 2 + drivers/clock_control/Kconfig.stm32 | 2 +- drivers/clock_control/clock_stm32_ll_mp13.c | 199 ++++++++++++++++++ .../clock_control/stm32_clock_control.h | 2 + 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 drivers/clock_control/clock_stm32_ll_mp13.c diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 1b8332cdc6f35..4016d73b5b9c2 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -55,6 +55,8 @@ if(CONFIG_CLOCK_CONTROL_STM32_CUBE) zephyr_library_sources_ifdef(CONFIG_CLOCK_STM32_MCO clock_stm32_mco.c) if(CONFIG_SOC_SERIES_STM32MP1X) zephyr_library_sources(clock_stm32_ll_mp1.c) +elseif(CONFIG_SOC_SERIES_STM32MP13X) + zephyr_library_sources(clock_stm32_ll_mp13.c) elseif(CONFIG_SOC_SERIES_STM32H7X) zephyr_library_sources(clock_stm32_ll_h7.c) elseif(CONFIG_SOC_SERIES_STM32H7RSX) diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index d99fa3b62eb29..9dacd04dbeac9 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -9,7 +9,7 @@ menuconfig CLOCK_CONTROL_STM32_CUBE depends on SOC_FAMILY_STM32 default y select USE_STM32_LL_UTILS - select USE_STM32_LL_RCC if (SOC_SERIES_STM32MP1X || SOC_SERIES_STM32H7X || \ + select USE_STM32_LL_RCC if (SOC_SERIES_STM32MP1X || SOC_SERIES_STM32MP13X || SOC_SERIES_STM32H7X || \ SOC_SERIES_STM32H7RSX || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || \ SOC_SERIES_STM32N6X) select RUNTIME_NMI if ($(dt_nodelabel_enabled,clk_hse) && \ diff --git a/drivers/clock_control/clock_stm32_ll_mp13.c b/drivers/clock_control/clock_stm32_ll_mp13.c new file mode 100644 index 0000000000000..6c8da819e5116 --- /dev/null +++ b/drivers/clock_control/clock_stm32_ll_mp13.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static int stm32_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system; + volatile int temp; + + ARG_UNUSED(dev); + + if (!IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX)) { + /* Attempt to toggle a wrong periph clock bit */ + return -ENOTSUP; + } + + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus, pclken->enr); + /* Ensure that the write operation is completed */ + temp = sys_read32(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus); + UNUSED(temp); + + return 0; +} + +static int stm32_clock_control_off(const struct device *dev, clock_control_subsys_t sub_system) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system; + volatile int temp; + + ARG_UNUSED(dev); + + if (!IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX)) { + /* Attempt to toggle a wrong periph clock bit */ + return -ENOTSUP; + } + + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus, pclken->enr); + /* Ensure that the write operation is completed */ + temp = sys_read32(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus); + UNUSED(temp); + + return 0; +} + +static int stm32_clock_control_get_subsys_rate(const struct device *dev, + clock_control_subsys_t sub_system, uint32_t *rate) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system; + + ARG_UNUSED(dev); + + switch (pclken->bus) { + case STM32_CLOCK_BUS_APB1: + switch (pclken->enr) { + case LL_APB1_GRP1_PERIPH_UART4: + *rate = LL_RCC_GetUARTClockFreq(LL_RCC_UART4_CLKSOURCE); + break; + default: + return -ENOTSUP; + } + break; + default: + return -ENOTSUP; + } + return 0; +} + +static const struct clock_control_driver_api stm32_clock_control_api = { + .on = stm32_clock_control_on, + .off = stm32_clock_control_off, + .get_rate = stm32_clock_control_get_subsys_rate, +}; + +static void set_up_fixed_clock_sources(void) +{ + if (IS_ENABLED(STM32_HSE_ENABLED)) { + /* Enable HSE */ + LL_RCC_HSE_Enable(); + while (LL_RCC_HSE_IsReady() != 1) { + /* Wait for HSE ready */ + } + } + + if (IS_ENABLED(STM32_HSI_ENABLED)) { + /* Enable HSI if not enabled */ + if (LL_RCC_HSI_IsReady() != 1) { + /* Enable HSI */ + LL_RCC_HSI_Enable(); + while (LL_RCC_HSI_IsReady() != 1) { + /* Wait for HSI ready */ + } + } + } +} + +static int stm32_clock_control_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + set_up_fixed_clock_sources(); + +#if STM32_SYSCLK_SRC_HSE + + LL_RCC_SetMPUClkSource(LL_RCC_MPU_CLKSOURCE_HSE); + while (LL_RCC_GetMPUClkSource() != LL_RCC_MPU_CLKSOURCE_HSE) { + } + +#elif STM32_SYSCLK_SRC_HSI + + LL_RCC_SetMPUClkSource(LL_RCC_MPU_CLKSOURCE_HSI); + while (LL_RCC_GetMPUClkSource() != LL_RCC_MPU_CLKSOURCE_HSI) { + } + +#elif STM32_SYSCLK_SRC_PLL + + BUILD_ASSERT(IS_ENABLED(STM32_HSE_ENABLED), + "STM32MP13 PLL requires HSE to be enabled!"); + + /* The default system clock source is HSI, but the bootloader may have switched it. */ + /* Switch back to HSE for clock setup as PLL1 configuration must not be modified */ + /* while active.*/ + + LL_RCC_SetMPUClkSource(LL_RCC_MPU_CLKSOURCE_HSE); + while ((READ_BIT(RCC->MPCKSELR, RCC_MPCKSELR_MPUSRCRDY) != RCC_MPCKSELR_MPUSRCRDY)) { + } + + CLEAR_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVPEN); + while (READ_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVPEN) == RCC_PLL1CR_DIVPEN) { + }; + + CLEAR_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVQEN); + while (READ_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVQEN) == RCC_PLL1CR_DIVQEN) { + }; + + CLEAR_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVREN); + while (READ_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVREN) == RCC_PLL1CR_DIVREN) { + }; + + uint32_t pll1_n = DT_PROP(DT_NODELABEL(pll1), mul_n); + uint32_t pll1_m = DT_PROP(DT_NODELABEL(pll1), div_m); + uint32_t pll1_p = DT_PROP(DT_NODELABEL(pll1), div_p); + uint32_t pll1_v = DT_PROP(DT_NODELABEL(pll1), frac_v); + + LL_RCC_PLL1_SetN(pll1_n); + while (LL_RCC_PLL1_GetN() != pll1_n) { + } + LL_RCC_PLL1_SetM(pll1_m); + while (LL_RCC_PLL1_GetM() != pll1_m) { + } + LL_RCC_PLL1_SetP(pll1_p); + while (LL_RCC_PLL1_GetP() != pll1_p) { + } + LL_RCC_PLL1_SetFRACV(pll1_v); + while (LL_RCC_PLL1_GetFRACV() != pll1_v) { + } + + LL_RCC_PLL1_Enable(); + while (LL_RCC_PLL1_IsReady() != 1) { + } + + SET_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVPEN); + while (READ_BIT(RCC->PLL1CR, RCC_PLL1CR_DIVPEN) != RCC_PLL1CR_DIVPEN) { + }; + + LL_RCC_SetMPUClkSource(LL_RCC_MPU_CLKSOURCE_PLL1); + while (LL_RCC_GetMPUClkSource() != LL_RCC_MPU_CLKSOURCE_PLL1) { + } + +#endif + + return 0; +} + +/** + * @brief RCC device, note that priority is intentionally set to 1 so + * that the device init runs just after SOC init + */ +DEVICE_DT_DEFINE(DT_NODELABEL(rcc), + stm32_clock_control_init, + NULL, + NULL, NULL, + PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &stm32_clock_control_api); diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index fddf67e4da5ea..49c74d1922bf1 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -53,6 +53,8 @@ #include #elif defined(CONFIG_SOC_SERIES_STM32H7RSX) #include +#elif defined(CONFIG_SOC_SERIES_STM32MP13X) +#include #elif defined(CONFIG_SOC_SERIES_STM32N6X) #include #elif defined(CONFIG_SOC_SERIES_STM32U0X) From 6ca2db681b32018ee2790b604e0208410f10a598 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Mon, 24 Mar 2025 09:32:39 +0100 Subject: [PATCH 10/11] dts: arm: st: mp13: stm32mp13 new series with cortex A7 Put the flash in DDR 0xC0000000 Put the SRAM in DDR 0xD0000000 Signed-off-by: Julien Racki --- dts/arm/st/mp13/stm32mp13.dtsi | 225 ++++++++++++++++++++++++++++++++ dts/arm/st/mp13/stm32mp135.dtsi | 13 ++ 2 files changed, 238 insertions(+) create mode 100644 dts/arm/st/mp13/stm32mp13.dtsi create mode 100644 dts/arm/st/mp13/stm32mp135.dtsi diff --git a/dts/arm/st/mp13/stm32mp13.dtsi b/dts/arm/st/mp13/stm32mp13.dtsi new file mode 100644 index 0000000000000..d781890d1b5f6 --- /dev/null +++ b/dts/arm/st/mp13/stm32mp13.dtsi @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + }; + }; + + soc { + interrupt-parent = <&gic>; + + sysram: memory@2ffe0000 { + compatible = "mmio-sram"; + reg = <0x2FFE0000 DT_SIZE_K(128)>; + }; + + uart4: serial@40010000 { + compatible = "st,stm32-uart"; + reg = <0x40010000 0x400>; + clocks = <&rcc STM32_CLOCK(APB1, 16)>; + resets = <&rctl STM32_RESET(APB1, 16)>; + interrupts = ; + status = "disabled"; + }; + + rcc: rcc@50000000 { + compatible = "st,stm32-rcc"; + reg = <0x50000000 0x1000>; + #clock-cells = <2>; + + rctl: reset-controller { + compatible = "st,stm32-rcc-rctl"; + #reset-cells = <1>; + set-bit-to-deassert; + }; + }; + + pinctrl: pin-controller@50002000 { + compatible = "st,stm32-pinctrl"; + reg = <0x50002000 0x9000>; + #address-cells = <1>; + #size-cells = <1>; + + gpioa: gpio@50002000 { + compatible = "st,stm32-gpio"; + reg = <0x50002000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 0)>; + }; + + gpiob: gpio@50003000 { + compatible = "st,stm32-gpio"; + reg = <0x50003000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 1)>; + }; + + gpioc: gpio@50004000 { + compatible = "st,stm32-gpio"; + reg = <0x50004000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 2)>; + }; + + gpiod: gpio@50005000 { + compatible = "st,stm32-gpio"; + reg = <0x50005000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 3)>; + }; + + gpioe: gpio@50006000 { + compatible = "st,stm32-gpio"; + reg = <0x50006000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 4)>; + }; + + gpiof: gpio@50007000 { + compatible = "st,stm32-gpio"; + reg = <0x50007000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 5)>; + }; + + gpiog: gpio@50008000 { + compatible = "st,stm32-gpio"; + reg = <0x50008000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 6)>; + }; + + gpioh: gpio@50009000 { + compatible = "st,stm32-gpio"; + reg = <0x50009000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 7)>; + }; + + gpioi: gpio@5000a000 { + compatible = "st,stm32-gpio"; + reg = <0x5000a000 0x400>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&rcc STM32_CLOCK(AHB4, 8)>; + }; + }; + + exti: interrupt-controller@5000d000 { + compatible = "st,stm32g0-exti","st,stm32-exti"; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <1>; + reg = <0x5000D000 0x400>; + num-lines = <16>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "line0", "line1", "line2", "line3", + "line4", "line5", "line6", "line7", + "line8", "line9", "line10", "line11", + "line12", "line13", "line14", "line15"; + line-ranges = <0 1>, <1 1>, <2 1>, <3 1>, + <4 1>, <5 1>, <6 1>, <7 1>, + <8 1>, <9 1>, <10 1>, <11 1>, + <12 1>, <13 1>, <14 1>, <15 1>; + }; + }; + + gic: gic@A0021000 { + compatible = "arm,gic-v2", "arm,gic"; + reg = <0xA0021000 0x1000>, + <0xA0022000 0x2000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + ddr_code: memory@C0000000 { + compatible = "mmio-sram"; + reg = <0xC0000000 0x10000000>; + }; + + ddr_data: memory@D0000000 { + compatible = "mmio-sram"; + reg = <0xD0000000 0x10000000>; + }; + + clocks { + + clk_hse: clk-hse { + #clock-cells = <0>; + compatible = "fixed-clock"; + status = "disabled"; + }; + + clk_hsi: clk-hsi { + #clock-cells = <0>; + compatible = "fixed-clock"; + status = "disabled"; + }; + + cpusw: cpusw { + #clock-cells = <0>; + compatible = "st,stm32mp13-cpu-clock-mux"; + status = "disabled"; + }; + + pll1: pll: pll { + #clock-cells = <0>; + compatible = "st,stm32mp13-pll-clock"; + status = "disabled"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; +}; diff --git a/dts/arm/st/mp13/stm32mp135.dtsi b/dts/arm/st/mp13/stm32mp135.dtsi new file mode 100644 index 0000000000000..4b754a69d583b --- /dev/null +++ b/dts/arm/st/mp13/stm32mp135.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + compatible = "st,stm32mp135", "st,stm32mp13", "simple-bus"; + }; +}; From b78c51c57494aa8045d2dffaa95e620d5b93c965 Mon Sep 17 00:00:00 2001 From: Julien Racki Date: Mon, 24 Mar 2025 09:37:28 +0100 Subject: [PATCH 11/11] boards: st: Add support for stm32mp135f_dk board Add support for STM32MP135F DK board. Signed-off-by: Julien Racki --- .../st/stm32mp135f_dk/Kconfig.stm32mp135f_dk | 5 + boards/st/stm32mp135f_dk/board.cmake | 6 + boards/st/stm32mp135f_dk/board.yml | 6 + .../doc/img/stm32mp135f_dk.webp | Bin 0 -> 39658 bytes boards/st/stm32mp135f_dk/doc/index.rst | 203 ++++++++++++++++++ boards/st/stm32mp135f_dk/stm32mp135f_dk.dts | 93 ++++++++ .../stm32mp135f_dk/stm32mp135f_dk_defconfig | 16 ++ boards/st/stm32mp135f_dk/support/Zephyr.tsv | 5 + boards/st/stm32mp135f_dk/support/openocd.cfg | 4 + boards/st/stm32mp135f_dk/twister.yaml | 14 ++ 10 files changed, 352 insertions(+) create mode 100644 boards/st/stm32mp135f_dk/Kconfig.stm32mp135f_dk create mode 100644 boards/st/stm32mp135f_dk/board.cmake create mode 100644 boards/st/stm32mp135f_dk/board.yml create mode 100644 boards/st/stm32mp135f_dk/doc/img/stm32mp135f_dk.webp create mode 100644 boards/st/stm32mp135f_dk/doc/index.rst create mode 100644 boards/st/stm32mp135f_dk/stm32mp135f_dk.dts create mode 100644 boards/st/stm32mp135f_dk/stm32mp135f_dk_defconfig create mode 100644 boards/st/stm32mp135f_dk/support/Zephyr.tsv create mode 100644 boards/st/stm32mp135f_dk/support/openocd.cfg create mode 100644 boards/st/stm32mp135f_dk/twister.yaml diff --git a/boards/st/stm32mp135f_dk/Kconfig.stm32mp135f_dk b/boards/st/stm32mp135f_dk/Kconfig.stm32mp135f_dk new file mode 100644 index 0000000000000..c648af34bc372 --- /dev/null +++ b/boards/st/stm32mp135f_dk/Kconfig.stm32mp135f_dk @@ -0,0 +1,5 @@ +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32MP135F_DK + select SOC_STM32MP135FXX diff --git a/boards/st/stm32mp135f_dk/board.cmake b/boards/st/stm32mp135f_dk/board.cmake new file mode 100644 index 0000000000000..af21b18031704 --- /dev/null +++ b/boards/st/stm32mp135f_dk/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) + +board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd.cfg") diff --git a/boards/st/stm32mp135f_dk/board.yml b/boards/st/stm32mp135f_dk/board.yml new file mode 100644 index 0000000000000..2e3886965ba73 --- /dev/null +++ b/boards/st/stm32mp135f_dk/board.yml @@ -0,0 +1,6 @@ +board: + name: stm32mp135f_dk + full_name: STM32MP135F-DK Discovery + vendor: st + socs: + - name: stm32mp135fxx diff --git a/boards/st/stm32mp135f_dk/doc/img/stm32mp135f_dk.webp b/boards/st/stm32mp135f_dk/doc/img/stm32mp135f_dk.webp new file mode 100644 index 0000000000000000000000000000000000000000..d4e5a32a261ac4dd9228570e7f2b8fbe1247b709 GIT binary patch literal 39658 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 literal 0 HcmV?d00001 diff --git a/boards/st/stm32mp135f_dk/doc/index.rst b/boards/st/stm32mp135f_dk/doc/index.rst new file mode 100644 index 0000000000000..9000f28bbfbe6 --- /dev/null +++ b/boards/st/stm32mp135f_dk/doc/index.rst @@ -0,0 +1,203 @@ +.. zephyr:board:: stm32mp135f_dk + +Overview +******** +The STM32MP135 Discovery kit (STM32MP135F-DK) leverages the capabilities of the +1 GHz STM32MP135 microprocessors to allow users to develop applications easily with Zephyr RTOS. + +It includes an ST-LINK embedded debug tool, LEDs, push-buttons, two 10/100 Mbit/s Ethernet (RMII) connectors, one USB Type-C |reg| connector, four USB Host Type-A connectors, and one microSD™ connector. + +To expand the functionality of the STM32MP135 Discovery kit, one GPIO expansion connector is also available for third-party shields. + +Additionally, the STM32MP135 Discovery kit features an LCD display with a touch panel, Wi‑Fi |reg| and Bluetooth |reg| Low Energy capability, and a 2-megapixel CMOS camera module. + +It also provides secure boot and cryptography features. + +Zephyr OS is ported to run on the Cortex |reg|-A7 core. + +- STM32MP135FAF7: Arm |reg| Cortex |reg|-A7 32-bit processor at 1 GHz, in a TFBGA320 package +- ST PMIC STPMIC1 +- 4-Gbit DDR3L, 16 bits, 533 MHz +- 4.3" 480x272 pixels LCD display module with capacitive touch panel and RGB interface +- UXGA 2-megapixel CMOS camera module (included) with MIPI CSI-2 |reg| / SMIA CCP2 deserializer +- Wi-Fi |reg| 802.11b/g/n +- Bluetooth |reg| Low Energy 4.1 +- Dual 10/100 Mbit/s Ethernet (RMII) compliant with IEEE-802.3u, one with Wake on LAN (WoL) support +- USB Host 4-port hub +- USB Type-C |reg| DRP based on an STM32G0 device +- 4 user LEDs +- 4 push-buttons (2× user, tamper, and reset) +- 1 wake-up button +- Board connectors: + + - Dual-lane MIPI CSI-2 |reg| camera module expansion + - 2x Ethernet RJ45 + - 4x USB Type-A + - USB Micro-B + - USB Type-C |reg| + - microSD™ card holder + - GPIO expansion + - 5 V / 3 A USB Type-C |reg| power supply input (charger not provided) + - VBAT for power backup + +- On-board current measurement +- On-board STLINK-V3E debugger/programmer with USB re-enumeration capability: + + - mass storage + - Virtual COM port + - debug port + +More information about the board can be found at the +`STM32P135 Discovery website`_. + +Hardware +******** + +More information about the STM32MP135F_DK board hardware can be found here: + +- `STM32MP135F_DK Hardware Description`_ + +More information about STM32P135F microprocessor can be found here: + +- `STM32MP135F on www.st.com`_ +- `STM32MP135F reference manual`_ + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +STM32MP135F-DK Discovery Board schematic is available here: +`STM32MP135F Discovery board schematics`_. + + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- USART_4 TX/RX : PD6/PD8 (UART console) + +- USER_BUTTON : PA13 +- LED_3 : PA14 +- LED_4 : PA13 + +System Clock +------------ + +The Cortex |reg|-A7 core is configured to run at a clock speed of up to 1GHz. + +Memory mapping +-------------- + ++------------+-----------------------+----------------+ +| Region | Address | Size | ++============+=======================+================+ +| SYSRAM | 0x2FFE0000-0x2FFFFFFF | 128KB | ++------------+-----------------------+----------------+ +| SRAM 1 | 0x30000000-0x30003FFF | 16KB | ++------------+-----------------------+----------------+ +| SRAM 2 | 0x30004000-0x30005FFF | 8KB | ++------------+-----------------------+----------------+ +| SRAM 3 | 0x30006000-0x30007FFF | 8KB | ++------------+-----------------------+----------------+ +| DDR | 0xC0000000-0xDFFFFFFF | 512 MB | ++------------+-----------------------+----------------+ + +Programming and Debugging +************************* + +Prerequisite +============ + +The STM32MP135 has a DDR controller that need to be initialized before loading the Zephyr example. + +One method to perform this is to flash the Zephyr executable, along with the DDR initialization script, on an SD card inserted in the board. To do so, you first need to :ref:`install STM32CubeProgrammer ` and download the `STM32CubeMP13 package`_. + +Signature and flashing +====================== + +After building the Zephyr project, you need to sign your binary file using the Stm32ImageAddHeader.py with the following command: + +.. code-block:: console + + python3 ${Path_to_STM32CubeMP13}/Utilities/ImageHeader/Python3/Stm32ImageAddHeader.py ${Path_to_build_dir}/zephyr/zephyr.bin ${STM32CubeMP13}/Projects/STM32MP135C-DK/External_Loader/Prebuild_Binaries/SD_Ext_Loader/zephyr_Signed.bin -bt 10 -la C0000000 -ep C0000000 + +Here -bt specifies the boot type, -la specifies the load address and -ep the entry point for your executable (same as the load address in this case). + +Then, copy :zephyr_file:`boards/st/stm32mp135f_dk/support/Zephyr.tsv` to ``${Path_to_STM32CubeMP13}/Projects/STM32MP135C-DK/External_Loader/Prebuild_Binaries/SD_Ext_Loader/``. + +Finally using the Cube Programmer select the Zephyr.tsv and flash the SD card with the following command: + +.. code-block:: console + + ${Path_to_STM32cube_Programmer}/bin/STM32_Programmer.sh -c port=${ConnectedPort} p=even br=115200 -d ${Path_to_STM32CubeMP13}/Projects/STM32MP135C-DK/External_Loader/Prebuild_Binaries/SD_Ext_Loader/Zephyr.tsv + +.. note:: + You can refer to this example to flash an example to the SD card: + `How to install STM32Cube software package on microSD card`_ + +Debugging +========= + +You can debug an application using OpenOCD and GDB. + +- Build the sample: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32mp135f_dk + :goals: build + +- Flash the SD card using: + `How to install STM32Cube software package on microSD card`_ + +- Run the application from the SD card + +- Attach to the target: + + .. code-block:: console + + west attach + +.. note:: + The ``run`` command of GDB isn't supported at the moment for this board. + +References +********** + +.. target-notes:: + +.. _STM32P135 Discovery website: + https://www.st.com/en/evaluation-tools/stm32mp135f-dk.html + +.. _STM32MP135F Discovery board User Manual: + https://www.st.com/resource/en/user_manual/dm00862450.pdf + +.. _STM32MP135F Discovery board schematics: + https://www.st.com/resource/en/schematic_pack/mb1635-mp135f-e02-schematic.pdf + +.. _STM32MP135F on www.st.com: + https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-arm-cortex-mpus/stm32mp1-series/stm32mp135/stm32mp135f.html + +.. _STM32MP135F reference manual: + https://www.st.com/resource/en/reference_manual/DM00670465-.pdf + +.. _STM32MP135 STM32Cube software package: + https://www.st.com/en/embedded-software/stm32cubemp13.html#get-software + +.. _How to install STM32Cube software package on microSD card: + https://wiki.st.com/stm32mpu/wiki/How_to_load_and_start_STM32CubeMP13_applications_via_microSD_card + +.. _STM32MP135F boot architecture: + https://wiki.st.com/stm32mpu/wiki/STM32CubeMP13_package_-_boot_architecture + +.. _STM32MP135F baremetal distribution: + https://wiki.st.com/stm32mpu/wiki/Category:Bare_metal_-_RTOS_embedded_software + +.. _STM32CubeMP13 package: + https://github.com/STMicroelectronics/STM32CubeMP13 + +.. _STM32MP135F_DK Hardware Description: + https://wiki.stmicroelectronics.cn/stm32mpu/wiki/STM32MP135x-DK_-_hardware_description diff --git a/boards/st/stm32mp135f_dk/stm32mp135f_dk.dts b/boards/st/stm32mp135f_dk/stm32mp135f_dk.dts new file mode 100644 index 0000000000000..5d2f343835568 --- /dev/null +++ b/boards/st/stm32mp135f_dk/stm32mp135f_dk.dts @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include + +/ { + model = "STMicroelectronics STM32MP135-DK board"; + compatible = "st,stm32mp135f-dk"; + + chosen { + zephyr,flash = &ddr_code; + zephyr,sram = &ddr_data; + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button: button { + label = "User 1"; + gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + blue_led_1: led_1 { + gpios = <&gpioa 14 GPIO_ACTIVE_HIGH>; + label = "LD3"; + }; + + red_led_2: led_2 { + gpios = <&gpioa 13 GPIO_ACTIVE_HIGH>; + label = "LD4"; + }; + }; + + aliases { + led0 = &blue_led_1; + led1 = &red_led_2; + sw0 = &user_button; + }; +}; + +&clk_hsi { + clock-frequency = ; + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&cpusw { + clocks = <&clk_hsi>; + clock-frequency = ; + status = "okay"; +}; + +&pll1 { + clocks = <&clk_hse>; + div-m = <2>; + mul-n = <83>; + div-p = <1>; + frac-v = <2730>; + status = "okay"; +}; + +&rcc { + clock-frequency = ; + clocks = <&pll>; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_tx_pd6 &uart4_rx_pd8>; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/st/stm32mp135f_dk/stm32mp135f_dk_defconfig b/boards/st/stm32mp135f_dk/stm32mp135f_dk_defconfig new file mode 100644 index 0000000000000..5a7682e99ddba --- /dev/null +++ b/boards/st/stm32mp135f_dk/stm32mp135f_dk_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2025, STMicroelectronics + +# SPDX-License-Identifier: Apache-2.0 + +# Enable GPIO +CONFIG_GPIO=y + +# Enable UART driver +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# Console (remote proc console by default) +CONFIG_CONSOLE=y + +# UART console (overrides remote proc console) +CONFIG_UART_CONSOLE=y diff --git a/boards/st/stm32mp135f_dk/support/Zephyr.tsv b/boards/st/stm32mp135f_dk/support/Zephyr.tsv new file mode 100644 index 0000000000000..9f59a34e9274e --- /dev/null +++ b/boards/st/stm32mp135f_dk/support/Zephyr.tsv @@ -0,0 +1,5 @@ +#Opt Id Name Type IP Offset Binary +P 0x1 fsbl-openbl Binary none 0x0 External_Mem_Loader_A7.stm32 +P 0x3 fsbl-extfl Binary none 0x0 SD_Ext_Loader.bin +P 0x4 fsbl-app Binary mmc0 0x0000080 FSBLA_Sdmmc1_A7_Signed.bin +P 0x5 fsbl-app Binary mmc0 0x0000500 zephyr_Signed.bin diff --git a/boards/st/stm32mp135f_dk/support/openocd.cfg b/boards/st/stm32mp135f_dk/support/openocd.cfg new file mode 100644 index 0000000000000..95aff7bb7ba7b --- /dev/null +++ b/boards/st/stm32mp135f_dk/support/openocd.cfg @@ -0,0 +1,4 @@ +source [find board/stm32mp13x_dk.cfg] + +# Don't reset the SoC to keep DDR configuration +reset_config none diff --git a/boards/st/stm32mp135f_dk/twister.yaml b/boards/st/stm32mp135f_dk/twister.yaml new file mode 100644 index 0000000000000..6e2d37a648298 --- /dev/null +++ b/boards/st/stm32mp135f_dk/twister.yaml @@ -0,0 +1,14 @@ +identifier: stm32mp135f_dk +name: ST STM32MP135F-DK Discovery +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - uart + - shell +ram: 256 +flash: 256 +vendor: st