From 2287cc7b2d9120467f86b24830aeb2b17c8230b8 Mon Sep 17 00:00:00 2001 From: Jan Zyczkowski Date: Sun, 23 Nov 2025 23:36:21 +0100 Subject: [PATCH 01/11] samples: radio_loader: Add radio core firmware loader Add radio_loader sample for nRF54H20 that implements a two-stage boot process for the radio core. The loader copies firmware from MRAM to TCM (Tightly Coupled Memory) at boot time and jumps to the loaded firmware. The loader uses devicetree chosen nodes to specify source and destination memory regions: - zephyr,loaded-fw-src: Source partition in MRAM - zephyr,loaded-fw-dst: Destination region in TCM JIRA: NCSDK-36461 Signed-off-by: Jan Zyczkowski --- samples/nrf54h20/radio_loader/CMakeLists.txt | 13 +++ samples/nrf54h20/radio_loader/app.overlay | 18 ++++ samples/nrf54h20/radio_loader/prj.conf | 94 ++++++++++++++++++++ samples/nrf54h20/radio_loader/src/main.c | 78 ++++++++++++++++ samples/nrf54h20/radio_loader/testcase.yaml | 12 +++ sysbuild/CMakeLists.txt | 1 + sysbuild/Kconfig.radioloader | 30 +++++++ sysbuild/Kconfig.sysbuild | 1 + sysbuild/radioloader.cmake | 28 ++++++ 9 files changed, 275 insertions(+) create mode 100644 samples/nrf54h20/radio_loader/CMakeLists.txt create mode 100644 samples/nrf54h20/radio_loader/app.overlay create mode 100644 samples/nrf54h20/radio_loader/prj.conf create mode 100644 samples/nrf54h20/radio_loader/src/main.c create mode 100644 samples/nrf54h20/radio_loader/testcase.yaml create mode 100644 sysbuild/Kconfig.radioloader create mode 100644 sysbuild/radioloader.cmake diff --git a/samples/nrf54h20/radio_loader/CMakeLists.txt b/samples/nrf54h20/radio_loader/CMakeLists.txt new file mode 100644 index 00000000000..24d2670bad9 --- /dev/null +++ b/samples/nrf54h20/radio_loader/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(loader) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/nrf54h20/radio_loader/app.overlay b/samples/nrf54h20/radio_loader/app.overlay new file mode 100644 index 00000000000..6850b954e7f --- /dev/null +++ b/samples/nrf54h20/radio_loader/app.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + + +/* Dummy chosen node to satisfy the build */ +/{ + chosen { + zephyr,loaded-fw-src = &cpuapp_slot0_partition; + zephyr,loaded-fw-dst = &cpurad_ram0; + }; +}; + +&cpuapp_slot0_partition { + reg = <0x92000 DT_SIZE_K(128)>; +}; diff --git a/samples/nrf54h20/radio_loader/prj.conf b/samples/nrf54h20/radio_loader/prj.conf new file mode 100644 index 00000000000..6f57c25fea8 --- /dev/null +++ b/samples/nrf54h20/radio_loader/prj.conf @@ -0,0 +1,94 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# ============================================================================== +# Optimized minimal configuration for radio_loader +# ============================================================================== +# This loader only runs SYS_INIT(load_and_jump_to_firmware, EARLY, 0) which: +# 1. Copies firmware from MRAM to TCM using memcpy() +# 2. Jumps to the loaded firmware's reset handler +# No Zephyr services, threading, or drivers are needed. +# +# Memory footprint target: < 4 KB + +# ============================================================================== +# Power Management +# ============================================================================== +CONFIG_PM=n +CONFIG_PM_DEVICE=n + +# ============================================================================== +# Kernel - Threading Disabled +# ============================================================================== +# We never reach main() or start the scheduler, so disable all threading +CONFIG_MULTITHREADING=n +CONFIG_MAIN_STACK_SIZE=512 +CONFIG_THREAD_STACK_INFO=n + +# Disable kernel features that require threading/scheduler +CONFIG_EVENTS=n +CONFIG_POLL=n +CONFIG_TIMESLICING=n + +# ============================================================================== +# Console, Debug, and Logging +# ============================================================================== +# No console output needed - loader jumps immediately to firmware +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_PRINTK=n +CONFIG_EARLY_CONSOLE=n +CONFIG_LOG=n + +# Banners and debug features +CONFIG_NCS_BOOT_BANNER=n +CONFIG_BOOT_BANNER=n +CONFIG_ERRNO=n + +# ============================================================================== +# Device Drivers +# ============================================================================== +# No peripheral drivers needed - we only use memcpy and jump +CONFIG_GPIO=n +CONFIG_PINCTRL=n +CONFIG_I2C=n +CONFIG_SPI=n +CONFIG_WATCHDOG=n + +# ============================================================================== +# Interrupt Management +# ============================================================================== +CONFIG_DYNAMIC_INTERRUPTS=n +CONFIG_IRQ_OFFLOAD=n +CONFIG_GEN_IRQ_VECTOR_TABLE=n +CONFIG_GEN_ISR_TABLES=n +CONFIG_GEN_SW_ISR_TABLE=n + +# ============================================================================== +# Hardware Protection +# ============================================================================== +CONFIG_HW_STACK_PROTECTION=n +CONFIG_ARM_MPU=n + +# ============================================================================== +# Security and Crypto +# ============================================================================== +# No crypto needed for simple memory copy operation +CONFIG_NRF_SECURITY=n +CONFIG_MBEDTLS_PSA_CRYPTO_C=n +CONFIG_PSA_CRYPTO_DRIVER_OBERON=n +CONFIG_PSA_CRYPTO=n +CONFIG_PSA_SSF_CRYPTO_CLIENT=n + +# ============================================================================== +# Memory Optimization +# ============================================================================== +CONFIG_HEAP_MEM_POOL_SIZE=0 +CONFIG_SYS_HEAP_RUNTIME_STATS=n + +# Use nano printf for minimal footprint (only used if PRINTK somehow gets enabled) +CONFIG_CBPRINTF_NANO=y diff --git a/samples/nrf54h20/radio_loader/src/main.c b/samples/nrf54h20/radio_loader/src/main.c new file mode 100644 index 00000000000..e1754b638c1 --- /dev/null +++ b/samples/nrf54h20/radio_loader/src/main.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include + +/* The loader uses devicetree chosen nodes to specify source + * and destination memory regions: + * - zephyr,loaded-fw-src: Source partition in NVM + * - zephyr,loaded-fw-dst: Destination region in RAM + */ + +#define LOADED_FW_NVM_NODE DT_CHOSEN(zephyr_loaded_fw_src) +#define LOADED_FW_NVM_PARTITION_NODE DT_PARENT(DT_PARENT(LOADED_FW_NVM_NODE)) +#define LOADED_FW_NVM_ADDR (DT_REG_ADDR(LOADED_FW_NVM_NODE) + \ + DT_REG_ADDR(LOADED_FW_NVM_PARTITION_NODE)) +#define LOADED_FW_NVM_SIZE DT_REG_SIZE(LOADED_FW_NVM_NODE) + +#define LOADED_FW_RAM_NODE DT_CHOSEN(zephyr_loaded_fw_dst) +#define LOADED_FW_RAM_ADDR DT_REG_ADDR(LOADED_FW_RAM_NODE) +#define LOADED_FW_RAM_SIZE DT_REG_SIZE(LOADED_FW_RAM_NODE) + +/* Verify devicetree configuration at build time */ +BUILD_ASSERT(DT_NODE_EXISTS(DT_CHOSEN(zephyr_loaded_fw_src)), + "Missing chosen node: zephyr,loaded-fw-src"); +BUILD_ASSERT(DT_NODE_EXISTS(DT_CHOSEN(zephyr_loaded_fw_dst)), + "Missing chosen node: zephyr,loaded-fw-dst"); +BUILD_ASSERT(LOADED_FW_NVM_SIZE <= LOADED_FW_RAM_SIZE, + "Firmware size exceeds available TCM RAM"); + +/** + * @brief Copy firmware from MRAM to TCM and jump to it + * + * This function runs as SYS_INIT(EARLY, 0) before main() and the scheduler. + * It copies the firmware from MRAM to TCM for optimal performance, then + * transfers execution to the loaded firmware's reset handler. + * + * This function never returns - execution transfers to the loaded firmware. + * + * @return 0 on success (never reached), -1 on failure (never reached) + */ +static int load_and_jump_to_firmware(void) +{ + /* Copy firmware from MRAM to TCM */ + memcpy((void *)LOADED_FW_RAM_ADDR, (void *)LOADED_FW_NVM_ADDR, LOADED_FW_NVM_SIZE); + + /* Extract reset handler from ARM Cortex-M vector table (entry 1) */ + uint32_t *vector_table = (uint32_t *)LOADED_FW_RAM_ADDR; + typedef void reset_handler_t(void); + reset_handler_t *reset_handler = (reset_handler_t *)(vector_table[1]); + + /* Jump to loaded firmware - this never returns */ + reset_handler(); + + /* Should never reach here */ + return -1; +} + +SYS_INIT(load_and_jump_to_firmware, EARLY, 0); + +/** + * @brief Main function - should never be reached + * + * If we reach main(), the firmware load and jump failed. + * This indicates a critical error in the loader. + */ +int main(void) +{ +#ifdef CONFIG_PRINTK + printk("ERROR: Firmware jump failed!\n"); +#endif + while (1) { + /* Hang here if jump fails */ + } + return -1; +} diff --git a/samples/nrf54h20/radio_loader/testcase.yaml b/samples/nrf54h20/radio_loader/testcase.yaml new file mode 100644 index 00000000000..b3583e1fc48 --- /dev/null +++ b/samples/nrf54h20/radio_loader/testcase.yaml @@ -0,0 +1,12 @@ +common: + sysbuild: true + tags: + - ci_build + - ci_samples_nrf54h20 + +tests: + radio_loader.nrf54h20dk_cpurad: + platform_allow: + - nrf54h20dk/nrf54h20/cpurad + integration_platforms: + - nrf54h20dk/nrf54h20/cpurad diff --git a/sysbuild/CMakeLists.txt b/sysbuild/CMakeLists.txt index 4f1791f37a7..359972ca9f3 100644 --- a/sysbuild/CMakeLists.txt +++ b/sysbuild/CMakeLists.txt @@ -1040,6 +1040,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/appcore.cmake) include(${CMAKE_CURRENT_LIST_DIR}/netcore.cmake) include(${CMAKE_CURRENT_LIST_DIR}/flprcore.cmake) include(${CMAKE_CURRENT_LIST_DIR}/pprcore.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/radioloader.cmake) include(${CMAKE_CURRENT_LIST_DIR}/secureboot.cmake) include(${CMAKE_CURRENT_LIST_DIR}/mcuboot.cmake) diff --git a/sysbuild/Kconfig.radioloader b/sysbuild/Kconfig.radioloader new file mode 100644 index 00000000000..4f459f877f7 --- /dev/null +++ b/sysbuild/Kconfig.radioloader @@ -0,0 +1,30 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config NRF_RADIO_LOADER + bool "Radio Core Firmware Loader [EXPERIMENTAL]" + depends on SOC_NRF54H20 + select EXPERIMENTAL + help + Enable the radio loader that copies firmware from MRAM to TCM + (Tightly Coupled Memory) at boot time. + + The loader runs from MRAM and: + - Copies firmware from MRAM partition to TCM + - Jumps to the loaded firmware in TCM for optimal performance + + Requires devicetree memory map configuration with partitions + and chosen nodes defined in the project's overlay files. + +if NRF_RADIO_LOADER + +config NRF_RADIO_LOADER_BOARD + string + default "nrf54h20dk/nrf54h20/cpurad" + help + Target board for the radio loader application. + +endif # NRF_RADIO_LOADER diff --git a/sysbuild/Kconfig.sysbuild b/sysbuild/Kconfig.sysbuild index 7c38969e12b..601c867fb78 100644 --- a/sysbuild/Kconfig.sysbuild +++ b/sysbuild/Kconfig.sysbuild @@ -81,6 +81,7 @@ rsource "Kconfig.appcore" rsource "Kconfig.flprcore" rsource "Kconfig.netcore" rsource "Kconfig.pprcore" +rsource "Kconfig.radioloader" rsource "Kconfig.secureboot" rsource "Kconfig.mcuboot" rsource "Kconfig.dfu" diff --git a/sysbuild/radioloader.cmake b/sysbuild/radioloader.cmake new file mode 100644 index 00000000000..47ea3a838c3 --- /dev/null +++ b/sysbuild/radioloader.cmake @@ -0,0 +1,28 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# Radio Loader sysbuild integration +# This file handles automatic integration of the radio_loader application + +if(SB_CONFIG_NRF_RADIO_LOADER) + message(STATUS "Adding radio_loader application") + message(STATUS "Board: ${SB_CONFIG_NRF_RADIO_LOADER_BOARD}") + + # Add radio_loader as an external Zephyr project + ExternalZephyrProject_Add( + APPLICATION radio_loader + SOURCE_DIR "${ZEPHYR_NRF_MODULE_DIR}/samples/nrf54h20/radio_loader" + BOARD ${SB_CONFIG_NRF_RADIO_LOADER_BOARD} + BOARD_REVISION ${BOARD_REVISION} + ) + + + UpdateableImage_Add(APPLICATION radio_loader) + # Note: Memory map configuration should be provided by the user project + # in: sysbuild/radio_loader/boards/.overlay + # This overlay should define partitions and chosen nodes for the loader + +endif() From 7e8bb54b44b6a930c78440b00bd8d3e879c89873 Mon Sep 17 00:00:00 2001 From: Jan Zyczkowski Date: Mon, 24 Nov 2025 08:28:09 +0100 Subject: [PATCH 02/11] sysbuild: Add support for relocation pattern in nRF54H20 Update sdk-zephyr revision and enhance Kconfig handling. If the 'fw-to-relocate' chosen node exists, the firmware will: - automatically calculate the Load Memory Address (LMA) adjustment for firmware relocation. - Modified Kconfig handling in cmake modules to accommodate a new property "fw-to-relocate". - Ensured backward compatibility by falling back to "zephyr,code-partition" if ther is not property "fw-to-relocate". JIRA: NCSDK-36461 Signed-off-by: Jan Zyczkowski --- cmake/modules/kconfig.cmake | 29 +++++++++++++++++-- cmake/sysbuild/sign_nrf54h20.cmake | 6 +++- soc/nordic/nrf54h/Kconfig.defconfig | 10 +++++++ .../nrf54h/Kconfig.defconfig.nrf54h20_cpurad | 20 +++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 soc/nordic/nrf54h/Kconfig.defconfig create mode 100644 soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index b84cef0a9fc..73910cabc0b 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -29,7 +29,11 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) else() include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/bootloader_dts_utils.cmake) - dt_chosen(code_partition PROPERTY "zephyr,code-partition") + dt_chosen(code_partition PROPERTY "fw-to-relocate") + if("${code_partition}" STREQUAL "") + dt_chosen(code_partition PROPERTY "zephyr,code-partition") + endif() + dt_partition_addr(code_partition_offset PATH "${code_partition}" REQUIRED) dt_reg_size(code_partition_size PATH "${code_partition}" REQUIRED) @@ -44,8 +48,24 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) # Additionally, convert primary slot dependencies to secondary slot dependencies. set(dotconfig_variant_content) foreach(line IN LISTS dotconfig_content) + dt_chosen(fw_to_relocate_property PROPERTY "fw-to-relocate") if("${line}" MATCHES "^CONFIG_FLASH_LOAD_OFFSET=.*$") - string(REGEX REPLACE "CONFIG_FLASH_LOAD_OFFSET=(.*)" "CONFIG_FLASH_LOAD_OFFSET=${code_partition_offset}" line ${line}) + # Change the CONFIG_FLASH_LOAD_OFFSET value only if the fw_to_relocate_property is empty - meaning that the firmware is not being relocated. + if("${fw_to_relocate_property}" STREQUAL "") + string(REGEX REPLACE "CONFIG_FLASH_LOAD_OFFSET=(.*)" "CONFIG_FLASH_LOAD_OFFSET=${code_partition_offset}" line ${line}) + endif() + endif() + + # Change the CONFIG_BUILD_OUTPUT_ADJUST_LMA value only if the fw_to_relocate_property is not empty - meaning that the firmware is being relocated. + if(NOT "${fw_to_relocate_property}" STREQUAL "") + if("${line}" MATCHES "^CONFIG_BUILD_OUTPUT_ADJUST_LMA=.*$") + + dt_partition_addr(fw_to_relocate_offset ABSOLUTE PATH "${fw_to_relocate_property}" REQUIRED) + dt_chosen(tcm_code_property PROPERTY "zephyr,code-partition") + dt_reg_addr(tcm_code_addr PATH "${tcm_code_property}" REQUIRED) + + string(REGEX REPLACE "CONFIG_BUILD_OUTPUT_ADJUST_LMA=(.*)" "CONFIG_BUILD_OUTPUT_ADJUST_LMA=${flash_base_addr}+${fw_to_relocate_offset}-${tcm_code_addr}" line ${line}) + endif() endif() if("${line}" MATCHES "^CONFIG_FLASH_LOAD_SIZE=.*$") @@ -62,7 +82,10 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) set(autoconf_variant_content) foreach(line IN LISTS autoconf_content) if("${line}" MATCHES "^#define CONFIG_FLASH_LOAD_OFFSET .*$") - string(REGEX REPLACE "#define CONFIG_FLASH_LOAD_OFFSET (.*)" "#define CONFIG_FLASH_LOAD_OFFSET ${code_partition_offset}" line ${line}) + # Change the CONFIG_FLASH_LOAD_OFFSET value only if the fw_to_relocate_property is empty - meaning that the firmware is not being relocated. + if("${fw_to_relocate_property}" STREQUAL "") + string(REGEX REPLACE "#define CONFIG_FLASH_LOAD_OFFSET (.*)" "#define CONFIG_FLASH_LOAD_OFFSET ${code_partition_offset}" line ${line}) + endif() endif() if("${line}" MATCHES "^#define CONFIG_FLASH_LOAD_SIZE .*$") diff --git a/cmake/sysbuild/sign_nrf54h20.cmake b/cmake/sysbuild/sign_nrf54h20.cmake index 6946ed0c785..79732d52c37 100644 --- a/cmake/sysbuild/sign_nrf54h20.cmake +++ b/cmake/sysbuild/sign_nrf54h20.cmake @@ -25,7 +25,11 @@ function(check_merged_slot_boundaries merged_partition images) set(end_offset) sysbuild_get(start_offset IMAGE ${image} VAR CONFIG_ROM_START_OFFSET KCONFIG) sysbuild_get(end_offset IMAGE ${image} VAR CONFIG_ROM_END_OFFSET KCONFIG) - dt_chosen(code_flash TARGET ${image} PROPERTY "zephyr,code-partition") + dt_chosen(code_flash TARGET ${image} PROPERTY "fw-to-relocate") + if("${code_flash}" STREQUAL "") + dt_chosen(code_flash TARGET ${image} PROPERTY "zephyr,code-partition") + endif() + dt_partition_addr(code_addr PATH "${code_flash}" TARGET ${image} REQUIRED ABSOLUTE) dt_reg_size(code_size TARGET ${image} PATH ${code_flash}) diff --git a/soc/nordic/nrf54h/Kconfig.defconfig b/soc/nordic/nrf54h/Kconfig.defconfig new file mode 100644 index 00000000000..f116209dec6 --- /dev/null +++ b/soc/nordic/nrf54h/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +if SOC_NRF54H20_CPURAD + +rsource "Kconfig.defconfig.nrf54h20_cpurad" + +endif # SOC_NRF54H20_CPURAD diff --git a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad new file mode 100644 index 00000000000..fae7a59ed32 --- /dev/null +++ b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -0,0 +1,20 @@ +# Nordic Semiconductor nRF54H20 Radio MCU + +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +if SOC_NRF54H20_CPURAD + +# Support for firmware relocation pattern (load from MRAM, run from TCM) +# If 'fw-to-relocate' chosen node exists, use it to calculate LMA adjustment +# Otherwise, fall back to standard code-partition calculation +DT_CHOSEN_FW_TO_RELOCATE = fw-to-relocate +DT_CHOSEN_Z_CODE = zephyr,code-partition +DT_CHOSEN_Z_SRAM = zephyr,sram + +config BUILD_OUTPUT_ADJUST_LMA + default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_FW_TO_RELOCATE)) - \ + $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE))" \ + if "$(dt_chosen_enabled,$(DT_CHOSEN_FW_TO_RELOCATE))" = "y" + +endif # SOC_NRF54H20_CPURAD From 5d0da1b2cb47a78ff3fde291d95c77fcfffa0c70 Mon Sep 17 00:00:00 2001 From: Jan Zyczkowski Date: Mon, 24 Nov 2025 08:30:00 +0100 Subject: [PATCH 03/11] samples: Add idle relocated TCM multicore test for nRF54H20 Introduce a new sample demonstrating a multicore idle test with firmware relocated to the radio core's TCM. The test showcases the radio loader pattern, where firmware is loaded from MRAM to TCM at runtime, ensuring efficient execution. JIRA: NCSDK-36461 Signed-off-by: Jan Zyczkowski --- CODEOWNERS | 3 + .../releases/release-notes-changelog.rst | 5 + doc/nrf/samples/other.rst | 1 + .../idle_relocated_tcm/CMakeLists.txt | 19 ++ .../idle_relocated_tcm/Kconfig.sysbuild | 24 ++ .../nrf54h20/idle_relocated_tcm/README.rst | 230 ++++++++++++++++++ .../boards/memory_map.overlay | 133 ++++++++++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 13 + samples/nrf54h20/idle_relocated_tcm/prj.conf | 12 + .../idle_relocated_tcm/remote/CMakeLists.txt | 13 + .../idle_relocated_tcm/remote/prj.conf | 8 + .../idle_relocated_tcm/remote/src/main.c | 32 +++ .../nrf54h20/idle_relocated_tcm/src/main.c | 28 +++ .../nrf54h20/idle_relocated_tcm/sysbuild.conf | 16 ++ .../sysbuild/mcuboot.overlay | 13 + .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 25 ++ .../sysbuild/radio_loader/prj.conf | 94 +++++++ .../radio_loader_secondary_app.overlay | 24 ++ .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 22 ++ .../sysbuild/remote_rad/prj.conf | 8 + .../sysbuild/remote_rad_secondary_app.overlay | 22 ++ .../nrf54h20/idle_relocated_tcm/testcase.yaml | 20 ++ 22 files changed, 765 insertions(+) create mode 100644 samples/nrf54h20/idle_relocated_tcm/CMakeLists.txt create mode 100644 samples/nrf54h20/idle_relocated_tcm/Kconfig.sysbuild create mode 100644 samples/nrf54h20/idle_relocated_tcm/README.rst create mode 100644 samples/nrf54h20/idle_relocated_tcm/boards/memory_map.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/prj.conf create mode 100644 samples/nrf54h20/idle_relocated_tcm/remote/CMakeLists.txt create mode 100644 samples/nrf54h20/idle_relocated_tcm/remote/prj.conf create mode 100644 samples/nrf54h20/idle_relocated_tcm/remote/src/main.c create mode 100644 samples/nrf54h20/idle_relocated_tcm/src/main.c create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild.conf create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/testcase.yaml diff --git a/CODEOWNERS b/CODEOWNERS index e73c1f9b3a2..74bb11d19d7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -523,6 +523,8 @@ /samples/nrf5340/empty_app_core/ @nrfconnect/ncs-si-muffin /samples/nrf5340/extxip_smp_svr/ @nrfconnect/ncs-eris /samples/nrf54h20/empty_app_core/ @nrfconnect/ncs-aurora +/samples/nrf54h20/idle_relocated_tcm/ @nrfconnect/ncs-si-muffin +/samples/nrf54h20/radio_loader/ @nrfconnect/ncs-si-muffin /samples/ironside_se/ @nrfconnect/ncs-aurora /samples/nrf_compress/ @nordicjm /samples/nrf_profiler/ @nrfconnect/ncs-si-bluebagel @@ -646,6 +648,7 @@ /samples/net/**/*.rst @nrfconnect/ncs-cia-doc /samples/net/coap_client/*.rst @nrfconnect/ncs-iot-oulu-tampere-doc /samples/nfc/**/*.rst @nrfconnect/ncs-si-muffin-doc +/samples/nrf54h20/idle_relocated_tcm/*.rst @nrfconnect/ncs-si-muffin-doc /samples/nrf5340/empty_app_core/*.rst @nrfconnect/ncs-si-muffin-doc /samples/nrf5340/extxip_smp_svr/*.rst @nrfconnect/ncs-eris-doc /samples/nrf5340/netboot/*.rst @nrfconnect/ncs-eris-doc diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 5698aabd25f..182ab4072f9 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -855,6 +855,11 @@ Other samples * Added a new testing step demonstrating how to calculate event propagation statistics. Also added the related test preset for the :file:`calc_stats.py` script (:file:`nrf/scripts/nrf_profiler/stats_nordic_presets/app_event_manager_profiler_tracer.json`). +* Added: + + * The :ref:`idle_relocated_tcm_sample` sample to demonstrate how to relocate the firmware to the TCM memory at boot time. + The sample also uses the ``radio_loader`` sample image (located in :file:`nrf/samples/nrf54h20/radio_loader`), which cannot be tested as a standalone sample, to relocate the firmware from the MRAM to the TCM memory at boot time. + Drivers ======= diff --git a/doc/nrf/samples/other.rst b/doc/nrf/samples/other.rst index c624d9c2cf4..88d72a0a453 100644 --- a/doc/nrf/samples/other.rst +++ b/doc/nrf/samples/other.rst @@ -25,3 +25,4 @@ This section lists single |NCS| samples for various uses that are not part of ot ../../../tests/benchmarks/multicore/*/README ../../../samples/zephyr/smp_svr_mini_boot/README ../../../samples/basic/*/README + ../../../samples/nrf54h20/*/README diff --git a/samples/nrf54h20/idle_relocated_tcm/CMakeLists.txt b/samples/nrf54h20/idle_relocated_tcm/CMakeLists.txt new file mode 100644 index 00000000000..a6d82c7d387 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(NOT SYSBUILD) + message(FATAL_ERROR + " This is a multi-image application that should be built using sysbuild.\n" + " Add --sysbuild argument to west build command to prepare all the images.") +endif() + +project(idle) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/nrf54h20/idle_relocated_tcm/Kconfig.sysbuild b/samples/nrf54h20/idle_relocated_tcm/Kconfig.sysbuild new file mode 100644 index 00000000000..c4db24c3b94 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/Kconfig.sysbuild @@ -0,0 +1,24 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +source "share/sysbuild/Kconfig" + +choice NETCORE + +default NETCORE_CUSTOM_RADIO + +config NETCORE_CUSTOM_RADIO + bool "Custom radio" + help + Use custom radio. + +endchoice + +config NETCORE_IMAGE_NAME + default "remote_rad" if NETCORE_CUSTOM_RADIO + +config NETCORE_IMAGE_PATH + default "$(ZEPHYR_NRF_MODULE_DIR)/samples/nrf54h20/idle_relocated_tcm/remote" if NETCORE_CUSTOM_RADIO diff --git a/samples/nrf54h20/idle_relocated_tcm/README.rst b/samples/nrf54h20/idle_relocated_tcm/README.rst new file mode 100644 index 00000000000..81defafa558 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/README.rst @@ -0,0 +1,230 @@ +.. _idle_relocated_tcm_sample: + +Multicore idle test with firmware relocated to radio core TCM +############################################################# + +.. contents:: + :local: + :depth: 2 + +The test benchmarks the idle behavior of an application that runs on multiple cores. +It demonstrates a radio loader pattern where the radio core firmware is loaded from MRAM into TCM (Tightly Coupled Memory) at runtime. + +Requirements +************ + +The test supports the following development kit: + +.. table-from-rows:: /includes/sample_board_rows.txt + :header: heading + :rows: nrf54h20dk_nrf54h20_cpuapp + +Overview +******** + +This test demonstrates how to build a multicore idle application with :ref:`configuration_system_overview_sysbuild` using a two-stage boot process for the radio core: + +* Radio Loader - A small bootloader that runs on the radio core, copies firmware from MRAM to TCM, and jumps to it. +* Remote Firmware - The actual application that runs from TCM after being loaded. + +The test automatically relocates the remote firmware binary to the correct MRAM address during build time, ensuring it can be loaded by the radio loader. + +Architecture +============ + +The system uses the following memory layout: + +* **MRAM (Non-volatile):** + + * ``cpurad_loader_partition`` @ 0x92000 - Contains the radio loader (8 KB) + * ``cpurad_loaded_fw`` @ 0x94000 - Contains the remote firmware binary (128 KB) + +* **TCM (Volatile, fast execution):** + + * ``cpurad_ram0`` @ 0x23000000 - Code execution region (128 KB) + * ``cpurad_data_ram`` @ 0x23020000 - Data region (64 KB) + +Additional files +================ + +The test comes with the following additional files: + +* :file:`sysbuild.conf` - Enables the radio loader by setting ``CONFIG_NRF_RADIO_LOADER=y``. +* :file:`boards/memory_map.overlay` - Shared memory map configuration for both loader and remote firmware. +* :file:`sysbuild/radio_loader/` - Radio loader configuration overrides (:file:`prj.conf`, overlay). +* :file:`sysbuild/remote_rad/` - Radio core firmware configuration overrides (:file:`prj.conf`, overlay). + +Enabling the Radio Loader +************************* + +The radio loader is automatically added to the build when you enable it in sysbuild configuration. + +In :file:`sysbuild.conf`: + +.. code-block:: kconfig + + SB_CONFIG_NRF_RADIO_LOADER=y + +This single configuration option: + +#. Automatically adds the ``radio_loader`` application located in the :file:`nrf/samples/nrf54h20/radio_loader` folder. +#. Builds it for the CPURAD core. +#. No manual ``ExternalZephyrProject_Add()`` needed in sysbuild. + +Memory map configuration +======================== + +The memory map is defined in :file:`boards/memory_map.overlay` and is shared between the radio loader and remote firmware to ensure consistency. + +The overlay defines: + +#. TCM regions: + + .. code-block:: devicetree + + cpurad_ram0: sram@23000000 { + compatible = "mmio-sram"; + reg = <0x23000000 0x20000>; /* 128 KB for code */ + }; + cpurad_data_ram: sram@23020000 { + compatible = "mmio-sram"; + reg = <0x23020000 0x10000>; /* 64 KB for data */ + }; + +#. MRAM partitions: + + .. code-block:: devicetree + + &mram1x { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cpurad_loader_partition: partition@92000 { + label = "cpurad_loader_partition"; + reg = <0x92000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */ + }; + + cpurad_loaded_fw: partition@94000 { + label = "cpurad_loaded_fw"; + reg = <0x94000 DT_SIZE_K(128)>; /* 128 KB fixed */ + }; + }; + }; + +Automatic firmware relocation +***************************** + +The remote firmware must be relocated to match the MRAM partition address where it will be stored. +This is automatically done by Zephyr's ``CONFIG_BUILD_OUTPUT_ADJUST_LMA`` feature when the devicetree chosen nodes are configured correctly. + +How it works +============ + +Firmware relocation is handled automatically by Zephyr's build system using the ``CONFIG_BUILD_OUTPUT_ADJUST_LMA`` configuration option, which is configured in ``zephyr/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad`` for all nRF54H20 CPURAD projects. + +The configuration automatically detects the ``fw-to-relocate`` chosen node in your devicetree. +When present, it calculates the LMA adjustment to relocate firmware from MRAM to TCM. +Without this chosen node, firmware runs directly from the ``zephyr,code-partition`` location (standard XIP behavior). + +Simply configure the devicetree chosen nodes correctly in your firmware's overlay: + +.. code-block:: devicetree + + /{ + chosen { + /* VMA: where code runs (TCM) */ + zephyr,code-partition = &cpurad_ram0; + zephyr,sram = &cpurad_data_ram; + + /* LMA: where to load from (MRAM partition) - enables relocation */ + fw-to-relocate = &cpurad_loaded_fw; + }; + }; + +Zephyr automatically calculates the Load Memory Address (LMA) adjustment based on your chosen nodes: + +**With fw-to-relocate chosen node** (for radio loader pattern): + +.. code-block:: text + + LMA_adjustment = fw-to-relocate address - zephyr,code-partition address + = cpurad_loaded_fw - cpurad_ram0 + = 0x94000 - 0x23000000 + +**Without fw-to-relocate** (standard behavior): + +.. code-block:: text + + LMA_adjustment = zephyr,code-partition address - zephyr,sram address + +The build system then adjusts the hex file so that the firmware is loaded from MRAM (``0x94000``), but runs from TCM (``0x23000000``). + +Building and running +******************** + +.. |test path| replace:: :file:`samples/nrf54h20/idle_relocated_tcm` + +.. include:: /includes/build_and_run_test.txt + +Testing +======= + +After programming the test to your development kit, complete the following steps to test it: + +1. |connect_terminal| +#. Reset the kit. +#. Observe the console output for both cores: + + * For the application core, the output should be as follows: + + .. code-block:: console + + *** Booting nRF Connect SDK zephyr-v3.5.0-3517-g9458a1aaf744 *** + build time: Nov 22 2025 17:00:59 + Multicore idle test on nrf54h20dk@0.9.0/nrf54h20/cpuapp + Multicore idle test iteration 0 + Multicore idle test iteration 1 + ... + + * For the radio core, the output should be as follows: + + .. code-block:: console + + *** Booting nRF Connect SDK zephyr-v3.5.0-3517-g9458a1aaf744 *** + build time: Nov 22 2025 17:00:29 + Multicore idle test on nrf54h20dk@0.9.0/nrf54h20/cpurad + Current PC (program counter) address: 0x23000ae0 + Multicore idle test iteration 0 + Multicore idle test iteration 1 + ... + + The radio loader first loads the firmware from MRAM (``0x0e094000``) to TCM (``0x23000000``) and then jumps to the loaded firmware. + This process is transparent and happens during the early boot stage. + +#. Verify the DFU process: + + #. Build the firmware for the secondary app slot, increase the version number in the :file:`prj.conf` file (uncomment the line): + + .. code-block:: kconfig + + CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.1+0" + + #. Build the firmware: + + .. code-block:: console + + west build -p -b nrf54h20dk/nrf54h20/cpuapp + + #. Program the firmware to the secondary application slot: + + .. code-block:: console + + nrfutil device program --firmware build/zephyr_secondary_app.merged.hex --options chip_erase_mode=ERASE_NONE + + Reset the development kit. + The firmware must boot from the secondary application slot. + Observe the change in build time in the console output. diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.overlay new file mode 100644 index 00000000000..d2449066251 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.overlay @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/{ + soc{ + cpurad_data_ram: sram@23020000 { + compatible = "mmio-sram"; + reg = < 0x23020000 0x10000 >; + #address-cells = < 0x1 >; + #size-cells = < 0x1 >; + ranges = < 0x0 0x23020000 0x10000 >; + }; + }; +}; + +&mram1x { + /delete-node/ partitions; + + /* Redefine the "partitions" DTS node. */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_boot_partition: boot_partition: partition@30000 { + reg = < 0x30000 0x10000 >; + label = "mcuboot"; + }; + + slot0_partition: partition@40000 { + reg = <0x40000 DT_SIZE_K(656)>; + }; + + cpuapp_slot0_partition: partition@40800 { + reg = <0x40800 DT_SIZE_K(326)>; + label = "image-0"; + }; + + cpurad_slot0_partition: cpurad_loader_partition: partition@92000 { + label = "cpurad_loader_partition"; + reg = <0x92000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */ + }; + + /* Remote firmware location in MRAM (fixed size for memcpy) */ + cpurad_loaded_fw: partition@94000 { + label = "cpurad_loaded_fw"; + reg = <0x94000 DT_SIZE_K(128)>; /* 128 KB fixed */ + }; + + cpurad_slot0_partition_container: partition@b2000 { + reg = <0xb2000 DT_SIZE_K(192)>; /* 238 - 128 - 8 = 192 KB allocated */ + }; + + cpuppr_code_partition: partition@e4000 { + reg = <0xe4000 DT_SIZE_K(64)>; + }; + + cpuflpr_code_partition: partition@f4000 { + reg = <0xf4000 DT_SIZE_K(48)>; + }; + + slot1_partition: partition@100000 { + reg = <0x100000 DT_SIZE_K(656)>; + }; + + cpuapp_slot1_partition: partition@100800 { + reg = <0x100800 DT_SIZE_K(326)>; + }; + + cpurad_loader_partition_slot1: cpurad_slot1_partition: partition@152000 { + label = "cpurad_loader_partition_slot1"; + reg = <0x152000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */ + }; + + /* Remote firmware location in MRAM (fixed size for memcpy) */ + cpurad_loaded_fw_slot1: partition@154000 { + label = "cpurad_loaded_fw_slot1"; + reg = <0x154000 DT_SIZE_K(128)>; /* 128 KB fixed */ + }; + + cpurad_slot1_partition_container: partition@174000 { + reg = <0x174000 DT_SIZE_K(192)>; /* 238 - 128 - 8 = 192 KB allocated */ + }; + + storage_partition: partition@1a4000 { + reg = <0x1a4000 DT_SIZE_K(40)>; + }; + + periphconf_partition: partition@1ae000 { + reg = <0x1ae000 DT_SIZE_K(8)>; + }; + + secondary_partition: partition@1b0000 { + reg = <0x1b0000 DT_SIZE_K(64)>; + }; + + secondary_periphconf_partition: partition@1c0000 { + reg = <0x1c0000 DT_SIZE_K(8)>; + }; + + /* NB: A gap has been left here for future partitions */ + + /* 0x1fd000 was chosen for secure_storage_partition such that + * there is no more space after secure_storage_partition. + */ + secure_storage_partition: partition@1fd000 { + compatible = "fixed-subpartitions"; + reg = <0x1fd000 DT_SIZE_K(12)>; + ranges = <0x0 0x1fd000 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_crypto_partition: partition@0 { + reg = <0x0 DT_SIZE_K(4)>; + }; + + cpurad_crypto_partition: partition@1000 { + reg = <0x1000 DT_SIZE_K(4)>; + }; + + cpuapp_its_partition: partition@2000 { + reg = <0x2000 DT_SIZE_K(2)>; + }; + + cpurad_its_partition: partition@2800 { + reg = <0x2800 DT_SIZE_K(2)>; + }; + }; + }; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..5685cb6b65f --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "memory_map.overlay" + +&cpuapp_data { + reg = <0x2f000000 0x40000>; +}; + +secondary_app_partition: &cpuapp_slot1_partition {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/prj.conf b/samples/nrf54h20/idle_relocated_tcm/prj.conf new file mode 100644 index 00000000000..d8e41511b6f --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/prj.conf @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_LOG=y + +CONFIG_SOC_NRF54H20_CPURAD_ENABLE=y + +# Set the version number for the firmware to verify dfu process +#CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.1+0" diff --git a/samples/nrf54h20/idle_relocated_tcm/remote/CMakeLists.txt b/samples/nrf54h20/idle_relocated_tcm/remote/CMakeLists.txt new file mode 100644 index 00000000000..e4fbb0131ca --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/remote/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(idle) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf b/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf new file mode 100644 index 00000000000..4191b264366 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_LOG=y +CONFIG_FLASH_BASE_ADDRESS=0x0 diff --git a/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c b/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c new file mode 100644 index 00000000000..d8b4d982081 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include + +LOG_MODULE_REGISTER(idle); + +int main(void) +{ + unsigned int cnt = 0; + uintptr_t pc; + + __asm__ volatile("adr %0, ." : "=r"(pc)); + LOG_INF("Multicore idle test on %s", CONFIG_BOARD_TARGET); + LOG_INF("Current PC (program counter) address: 0x%lx\n", (unsigned long)pc); + + /* using __TIME__ ensure that a new binary will be built on every + * compile which is convenient when testing firmware upgrade. + */ + LOG_INF("build time: " __DATE__ " " __TIME__); + + while (1) { + LOG_INF("Multicore idle test iteration %u", cnt++); + k_msleep(2000); + } + + return 0; +} diff --git a/samples/nrf54h20/idle_relocated_tcm/src/main.c b/samples/nrf54h20/idle_relocated_tcm/src/main.c new file mode 100644 index 00000000000..8bfa569648e --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/src/main.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include + +LOG_MODULE_REGISTER(idle); + +int main(void) +{ + unsigned int cnt = 0; + + /* using __TIME__ ensure that a new binary will be built on every + * compile which is convenient when testing firmware upgrade. + */ + LOG_INF("build time: " __DATE__ " " __TIME__); + + LOG_INF("Multicore idle test on %s", CONFIG_BOARD_TARGET); + while (1) { + LOG_INF("Multicore idle test iteration %u", cnt++); + k_msleep(2000); + } + + return 0; +} diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild.conf new file mode 100644 index 00000000000..5f95387545a --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild.conf @@ -0,0 +1,16 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# This automatically adds the radio_loader application to the build +SB_CONFIG_NRF_RADIO_LOADER=y +SB_CONFIG_NETCORE_CUSTOM_RADIO=y + +SB_CONFIG_BOOTLOADER_MCUBOOT=y +SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP=y +SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519=y +SB_CONFIG_BOOT_SIGNATURE_TYPE_PURE=y +# Reserve space for MCUboot trailer in CPURAD slots +SB_CONFIG_MCUBOOT_IMAGES_ROM_END_OFFSET_AUTO="remote_rad;remote_rad_secondary_app" diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay new file mode 100644 index 00000000000..284946af590 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../boards/memory_map.overlay" + +/ { + chosen { + zephyr,code-partition = &boot_partition; + }; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..e81c8ee3c8b --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../../../boards/memory_map.overlay" + +/{ + chosen { + zephyr,code-partition = &cpurad_loader_partition; + zephyr,sram = &cpurad_data_ram; + zephyr,loaded-fw-src = &cpurad_loaded_fw; + zephyr,loaded-fw-dst = &cpurad_ram0; + }; +}; + +&cpurad_ram0 { + compatible = "mmio-sram"; + /delete-property/ reg; + reg = < 0x23000000 0x20000 >; + ranges = < 0x0 0x23000000 0x20000 >; +}; + +secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf new file mode 100644 index 00000000000..6f57c25fea8 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf @@ -0,0 +1,94 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# ============================================================================== +# Optimized minimal configuration for radio_loader +# ============================================================================== +# This loader only runs SYS_INIT(load_and_jump_to_firmware, EARLY, 0) which: +# 1. Copies firmware from MRAM to TCM using memcpy() +# 2. Jumps to the loaded firmware's reset handler +# No Zephyr services, threading, or drivers are needed. +# +# Memory footprint target: < 4 KB + +# ============================================================================== +# Power Management +# ============================================================================== +CONFIG_PM=n +CONFIG_PM_DEVICE=n + +# ============================================================================== +# Kernel - Threading Disabled +# ============================================================================== +# We never reach main() or start the scheduler, so disable all threading +CONFIG_MULTITHREADING=n +CONFIG_MAIN_STACK_SIZE=512 +CONFIG_THREAD_STACK_INFO=n + +# Disable kernel features that require threading/scheduler +CONFIG_EVENTS=n +CONFIG_POLL=n +CONFIG_TIMESLICING=n + +# ============================================================================== +# Console, Debug, and Logging +# ============================================================================== +# No console output needed - loader jumps immediately to firmware +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_SERIAL=n +CONFIG_PRINTK=n +CONFIG_EARLY_CONSOLE=n +CONFIG_LOG=n + +# Banners and debug features +CONFIG_NCS_BOOT_BANNER=n +CONFIG_BOOT_BANNER=n +CONFIG_ERRNO=n + +# ============================================================================== +# Device Drivers +# ============================================================================== +# No peripheral drivers needed - we only use memcpy and jump +CONFIG_GPIO=n +CONFIG_PINCTRL=n +CONFIG_I2C=n +CONFIG_SPI=n +CONFIG_WATCHDOG=n + +# ============================================================================== +# Interrupt Management +# ============================================================================== +CONFIG_DYNAMIC_INTERRUPTS=n +CONFIG_IRQ_OFFLOAD=n +CONFIG_GEN_IRQ_VECTOR_TABLE=n +CONFIG_GEN_ISR_TABLES=n +CONFIG_GEN_SW_ISR_TABLE=n + +# ============================================================================== +# Hardware Protection +# ============================================================================== +CONFIG_HW_STACK_PROTECTION=n +CONFIG_ARM_MPU=n + +# ============================================================================== +# Security and Crypto +# ============================================================================== +# No crypto needed for simple memory copy operation +CONFIG_NRF_SECURITY=n +CONFIG_MBEDTLS_PSA_CRYPTO_C=n +CONFIG_PSA_CRYPTO_DRIVER_OBERON=n +CONFIG_PSA_CRYPTO=n +CONFIG_PSA_SSF_CRYPTO_CLIENT=n + +# ============================================================================== +# Memory Optimization +# ============================================================================== +CONFIG_HEAP_MEM_POOL_SIZE=0 +CONFIG_SYS_HEAP_RUNTIME_STATS=n + +# Use nano printf for minimal footprint (only used if PRINTK somehow gets enabled) +CONFIG_CBPRINTF_NANO=y diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay new file mode 100644 index 00000000000..6b7a55f3389 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../boards/memory_map.overlay" + +/{ + chosen { + zephyr,loaded-fw-src = &cpurad_loaded_fw_slot1; + zephyr,loaded-fw-dst = &cpurad_ram0; + zephyr,sram = &cpurad_data_ram; + }; +}; + +&cpurad_ram0 { + compatible = "mmio-sram"; + /delete-property/ reg; + reg = < 0x23000000 0x20000 >; + ranges = < 0x0 0x23000000 0x20000 >; +}; + +secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..08960044832 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../../../boards/memory_map.overlay" + +/{ + chosen { + zephyr,code-partition = &cpurad_ram0; + zephyr,sram = &cpurad_data_ram; + fw-to-relocate = &cpurad_loaded_fw; + }; +}; + +&cpurad_ram0 { + compatible = "mmio-sram"; + /delete-property/ reg; + reg = < 0x23000000 0x20000 >; + ranges = < 0x0 0x23000000 0x20000 >; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf new file mode 100644 index 00000000000..4191b264366 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_LOG=y +CONFIG_FLASH_BASE_ADDRESS=0x0 diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay new file mode 100644 index 00000000000..2a57ad60ed0 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../boards/memory_map.overlay" + +/{ + chosen { + fw-to-relocate = &cpurad_loaded_fw_slot1; + }; +}; + +&cpurad_ram0 { + compatible = "mmio-sram"; + /delete-property/ reg; + reg = < 0x23000000 0x20000 >; + ranges = < 0x0 0x23000000 0x20000 >; +}; + +secondary_app_partition: &cpurad_ram0 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/testcase.yaml b/samples/nrf54h20/idle_relocated_tcm/testcase.yaml new file mode 100644 index 00000000000..702e4dd2e27 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/testcase.yaml @@ -0,0 +1,20 @@ +common: + sysbuild: true + tags: + - ci_build + - ci_samples_nrf54h20 + harness_config: + type: multi_line + ordered: true + regex: + - "Multicore idle test on" + - "Multicore idle test iteration 0" + - "Multicore idle test iteration 1" + +tests: + benchmarks.multicore.idle_relocated_tcm.nrf54h20dk_cpuapp_cpurad: + harness: console + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp From 8aed0b247c1e9faeda9d155bb9365bdda3f5da5d Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Fri, 28 Nov 2025 14:30:07 +0100 Subject: [PATCH 04/11] samples: idle_relocated_tcm: Change memory_map.overlay to .dtsi Changes the *.overlay suffix to *.dtsi as it is included in other files. Jira: NCSDK-36461 Signed-off-by: Mateusz Kapala --- .../boards/{memory_map.overlay => memory_map.dtsi} | 0 .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 2 +- samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay | 2 +- .../radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay | 2 +- .../sysbuild/radio_loader_secondary_app.overlay | 2 +- .../remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay | 2 +- .../sysbuild/remote_rad_secondary_app.overlay | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename samples/nrf54h20/idle_relocated_tcm/boards/{memory_map.overlay => memory_map.dtsi} (100%) diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi similarity index 100% rename from samples/nrf54h20/idle_relocated_tcm/boards/memory_map.overlay rename to samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 5685cb6b65f..2f2d29e7814 100644 --- a/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "memory_map.overlay" +#include "memory_map.dtsi" &cpuapp_data { reg = <0x2f000000 0x40000>; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay index 284946af590..9312764c429 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "../boards/memory_map.overlay" +#include "../boards/memory_map.dtsi" / { chosen { diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay index e81c8ee3c8b..b000cf21c5b 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "../../../boards/memory_map.overlay" +#include "../../../boards/memory_map.dtsi" /{ chosen { diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay index 6b7a55f3389..8d1e0b76e08 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "../boards/memory_map.overlay" +#include "../boards/memory_map.dtsi" /{ chosen { diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay index 08960044832..2eca1c59dec 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "../../../boards/memory_map.overlay" +#include "../../../boards/memory_map.dtsi" /{ chosen { diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay index 2a57ad60ed0..353c789aaad 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "../boards/memory_map.overlay" +#include "../boards/memory_map.dtsi" /{ chosen { From 1e35dae7d885d67c6991a4c85e844c107641a71b Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Fri, 28 Nov 2025 13:02:44 +0100 Subject: [PATCH 05/11] cmake: sysbuild: Fix slot size for direct-xip image signing Fixed slot size used for signing the images when the MCUboot works in the direct-xip mode. Previously slot size was always taken from the slot0 partition instead of the zephyr,code-partition. Jira: NCSDK-36461 Signed-off-by: Mateusz Kapala --- cmake/sysbuild/image_signing.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/sysbuild/image_signing.cmake b/cmake/sysbuild/image_signing.cmake index de833a9e812..bb1a35707d0 100644 --- a/cmake/sysbuild/image_signing.cmake +++ b/cmake/sysbuild/image_signing.cmake @@ -90,6 +90,7 @@ function(zephyr_mcuboot_tasks) if(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT OR CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) dt_chosen(code_partition PROPERTY "zephyr,code-partition") dt_partition_addr(code_partition_offset PATH "${code_partition}" REQUIRED) + dt_reg_size(slot_size PATH "${code_partition}" REQUIRED) set(imgtool_rom_command --rom-fixed ${code_partition_offset}) endif() set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --align ${write_block_size} --slot-size ${slot_size} --header-size ${CONFIG_ROM_START_OFFSET} ${imgtool_rom_command}) From 77836702c6b20ad4e52041e175d9eeac038d5afc Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Fri, 28 Nov 2025 13:17:10 +0100 Subject: [PATCH 06/11] sysbuild: Switch from fw-to-relocate node to CONFIG_XIP=n It is possible for Zephyr to relocate code from NVM to RAM without using custom fw-to-relocate DTS node. The CONFIG_XIP=n needs to be used instead. This change aligns it at the build system level. Jira: NCSDK-36461 Signed-off-by: Mateusz Kapala --- cmake/modules/kconfig.cmake | 42 +++++++------------ cmake/sysbuild/sign_nrf54h20.cmake | 5 +-- .../nrf54h/Kconfig.defconfig.nrf54h20_cpurad | 10 ++--- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index 73910cabc0b..9255cfc7ba2 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -29,14 +29,15 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) else() include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/bootloader_dts_utils.cmake) - dt_chosen(code_partition PROPERTY "fw-to-relocate") - if("${code_partition}" STREQUAL "") - dt_chosen(code_partition PROPERTY "zephyr,code-partition") - endif() - + dt_chosen(code_partition PROPERTY "zephyr,code-partition") dt_partition_addr(code_partition_offset PATH "${code_partition}" REQUIRED) dt_reg_size(code_partition_size PATH "${code_partition}" REQUIRED) + # Needed for the CONFIG_BUILD_OUTPUT_ADJUST_LMA calculation. + dt_partition_addr(code_partition_abs_addr PATH "${code_partition}" REQUIRED ABSOLUTE) + dt_chosen(sram_property PROPERTY "zephyr,sram") + dt_reg_addr(sram_addr PATH "${sram_property}" REQUIRED) + set(preload_autoconf_h ${PRELOAD_BINARY_DIR}/zephyr/include/generated/zephyr/autoconf.h) set(preload_dotconfig ${PRELOAD_BINARY_DIR}/zephyr/.config) @@ -48,24 +49,8 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) # Additionally, convert primary slot dependencies to secondary slot dependencies. set(dotconfig_variant_content) foreach(line IN LISTS dotconfig_content) - dt_chosen(fw_to_relocate_property PROPERTY "fw-to-relocate") if("${line}" MATCHES "^CONFIG_FLASH_LOAD_OFFSET=.*$") - # Change the CONFIG_FLASH_LOAD_OFFSET value only if the fw_to_relocate_property is empty - meaning that the firmware is not being relocated. - if("${fw_to_relocate_property}" STREQUAL "") - string(REGEX REPLACE "CONFIG_FLASH_LOAD_OFFSET=(.*)" "CONFIG_FLASH_LOAD_OFFSET=${code_partition_offset}" line ${line}) - endif() - endif() - - # Change the CONFIG_BUILD_OUTPUT_ADJUST_LMA value only if the fw_to_relocate_property is not empty - meaning that the firmware is being relocated. - if(NOT "${fw_to_relocate_property}" STREQUAL "") - if("${line}" MATCHES "^CONFIG_BUILD_OUTPUT_ADJUST_LMA=.*$") - - dt_partition_addr(fw_to_relocate_offset ABSOLUTE PATH "${fw_to_relocate_property}" REQUIRED) - dt_chosen(tcm_code_property PROPERTY "zephyr,code-partition") - dt_reg_addr(tcm_code_addr PATH "${tcm_code_property}" REQUIRED) - - string(REGEX REPLACE "CONFIG_BUILD_OUTPUT_ADJUST_LMA=(.*)" "CONFIG_BUILD_OUTPUT_ADJUST_LMA=${flash_base_addr}+${fw_to_relocate_offset}-${tcm_code_addr}" line ${line}) - endif() + string(REGEX REPLACE "CONFIG_FLASH_LOAD_OFFSET=(.*)" "CONFIG_FLASH_LOAD_OFFSET=${code_partition_offset}" line ${line}) endif() if("${line}" MATCHES "^CONFIG_FLASH_LOAD_SIZE=.*$") @@ -76,16 +61,17 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) string(REGEX REPLACE "primary" "secondary" line ${line}) endif() + if("${line}" MATCHES "^CONFIG_BUILD_OUTPUT_ADJUST_LMA=.*$") + string(REGEX REPLACE "CONFIG_BUILD_OUTPUT_ADJUST_LMA=(.*)" "CONFIG_BUILD_OUTPUT_ADJUST_LMA=\"${code_partition_abs_addr}-${sram_addr}\"" line ${line}) + endif() + list(APPEND dotconfig_variant_content "${line}\n") endforeach() set(autoconf_variant_content) foreach(line IN LISTS autoconf_content) if("${line}" MATCHES "^#define CONFIG_FLASH_LOAD_OFFSET .*$") - # Change the CONFIG_FLASH_LOAD_OFFSET value only if the fw_to_relocate_property is empty - meaning that the firmware is not being relocated. - if("${fw_to_relocate_property}" STREQUAL "") - string(REGEX REPLACE "#define CONFIG_FLASH_LOAD_OFFSET (.*)" "#define CONFIG_FLASH_LOAD_OFFSET ${code_partition_offset}" line ${line}) - endif() + string(REGEX REPLACE "#define CONFIG_FLASH_LOAD_OFFSET (.*)" "#define CONFIG_FLASH_LOAD_OFFSET ${code_partition_offset}" line ${line}) endif() if("${line}" MATCHES "^#define CONFIG_FLASH_LOAD_SIZE .*$") @@ -96,6 +82,10 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) string(REGEX REPLACE "primary" "secondary" line ${line}) endif() + if("${line}" MATCHES "^#define CONFIG_BUILD_OUTPUT_ADJUST_LMA .*$") + string(REGEX REPLACE "#define CONFIG_BUILD_OUTPUT_ADJUST_LMA (.*)" "#define CONFIG_BUILD_OUTPUT_ADJUST_LMA \"${code_partition_abs_addr}-${sram_addr}\"" line ${line}) + endif() + list(APPEND autoconf_variant_content "${line}\n") endforeach() diff --git a/cmake/sysbuild/sign_nrf54h20.cmake b/cmake/sysbuild/sign_nrf54h20.cmake index 79732d52c37..8ace02403e8 100644 --- a/cmake/sysbuild/sign_nrf54h20.cmake +++ b/cmake/sysbuild/sign_nrf54h20.cmake @@ -25,10 +25,7 @@ function(check_merged_slot_boundaries merged_partition images) set(end_offset) sysbuild_get(start_offset IMAGE ${image} VAR CONFIG_ROM_START_OFFSET KCONFIG) sysbuild_get(end_offset IMAGE ${image} VAR CONFIG_ROM_END_OFFSET KCONFIG) - dt_chosen(code_flash TARGET ${image} PROPERTY "fw-to-relocate") - if("${code_flash}" STREQUAL "") - dt_chosen(code_flash TARGET ${image} PROPERTY "zephyr,code-partition") - endif() + dt_chosen(code_flash TARGET ${image} PROPERTY "zephyr,code-partition") dt_partition_addr(code_addr PATH "${code_flash}" TARGET ${image} REQUIRED ABSOLUTE) dt_reg_size(code_size TARGET ${image} PATH ${code_flash}) diff --git a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad index fae7a59ed32..c3608609326 100644 --- a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad +++ b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -5,16 +5,12 @@ if SOC_NRF54H20_CPURAD -# Support for firmware relocation pattern (load from MRAM, run from TCM) -# If 'fw-to-relocate' chosen node exists, use it to calculate LMA adjustment -# Otherwise, fall back to standard code-partition calculation -DT_CHOSEN_FW_TO_RELOCATE = fw-to-relocate DT_CHOSEN_Z_CODE = zephyr,code-partition DT_CHOSEN_Z_SRAM = zephyr,sram config BUILD_OUTPUT_ADJUST_LMA - default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_FW_TO_RELOCATE)) - \ - $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE))" \ - if "$(dt_chosen_enabled,$(DT_CHOSEN_FW_TO_RELOCATE))" = "y" + depends on !XIP + default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_Z_CODE)) - \ + $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_SRAM))" endif # SOC_NRF54H20_CPURAD From 45a907282b4e7af3e57b417978d905a7d9aa3e23 Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Fri, 28 Nov 2025 14:13:28 +0100 Subject: [PATCH 07/11] samples: idle_relocated_tcm: Adapt remote_rad to use CONFIG_XIP=n Instead of fw-to-relocate DTS note use the CONFIG_XIP=n. Align memory map to use whole TCM. Jira: NCSDK-36461 Signed-off-by: Mateusz Kapala --- .../idle_relocated_tcm/boards/memory_map.dtsi | 31 ++++++++++++------- .../boards/memory_map_ram_cpurad.dtsi | 13 ++++++++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 2 +- .../idle_relocated_tcm/remote/prj.conf | 3 +- .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 10 ++---- .../radio_loader_secondary_app.overlay | 10 ++---- .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 13 +++----- .../sysbuild/remote_rad/prj.conf | 3 +- .../sysbuild/remote_rad_secondary_app.overlay | 13 +++----- 9 files changed, 50 insertions(+), 48 deletions(-) create mode 100644 samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_cpurad.dtsi diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi index d2449066251..b40c11046b5 100644 --- a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi @@ -6,12 +6,13 @@ /{ soc{ - cpurad_data_ram: sram@23020000 { + /* Small piece of Global RAM for the radio loader to use during FW relocation. */ + cpurad_loader_ram: sram@2f039000 { compatible = "mmio-sram"; - reg = < 0x23020000 0x10000 >; + reg = < 0x2f039000 0x1000 >; #address-cells = < 0x1 >; #size-cells = < 0x1 >; - ranges = < 0x0 0x23020000 0x10000 >; + ranges = < 0x0 0x2f039000 0x1000 >; }; }; }; @@ -30,28 +31,32 @@ label = "mcuboot"; }; + /* Image 0, slot 0 (primary slot): merged application and radio core images. */ slot0_partition: partition@40000 { reg = <0x40000 DT_SIZE_K(656)>; }; + /* Application code for cpuapp core. */ cpuapp_slot0_partition: partition@40800 { reg = <0x40800 DT_SIZE_K(326)>; label = "image-0"; }; + /* Radio core firmware loader code for cpurad core. */ cpurad_slot0_partition: cpurad_loader_partition: partition@92000 { label = "cpurad_loader_partition"; reg = <0x92000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */ }; - /* Remote firmware location in MRAM (fixed size for memcpy) */ + /* Radio core application code relocated from MRAM to TCM for cpurad core. */ cpurad_loaded_fw: partition@94000 { label = "cpurad_loaded_fw"; - reg = <0x94000 DT_SIZE_K(128)>; /* 128 KB fixed */ + reg = <0x94000 DT_SIZE_K(192)>; }; - cpurad_slot0_partition_container: partition@b2000 { - reg = <0xb2000 DT_SIZE_K(192)>; /* 238 - 128 - 8 = 192 KB allocated */ + /* Remaining space in the slot 0. */ + cpurad_slot0_partition_container: partition@c4000 { + reg = <0xc4000 DT_SIZE_K(128)>; }; cpuppr_code_partition: partition@e4000 { @@ -62,27 +67,31 @@ reg = <0xf4000 DT_SIZE_K(48)>; }; + /* Image 0, slot 1 (secondary slot): merged application and radio core images. */ slot1_partition: partition@100000 { reg = <0x100000 DT_SIZE_K(656)>; }; + /* Application code for cpuapp core. */ cpuapp_slot1_partition: partition@100800 { reg = <0x100800 DT_SIZE_K(326)>; }; + /* Radio core firmware loader code for cpurad core. */ cpurad_loader_partition_slot1: cpurad_slot1_partition: partition@152000 { label = "cpurad_loader_partition_slot1"; reg = <0x152000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */ }; - /* Remote firmware location in MRAM (fixed size for memcpy) */ + /* Radio core application code relocated from MRAM to TCM for cpurad core. */ cpurad_loaded_fw_slot1: partition@154000 { label = "cpurad_loaded_fw_slot1"; - reg = <0x154000 DT_SIZE_K(128)>; /* 128 KB fixed */ + reg = <0x154000 DT_SIZE_K(192)>; }; - cpurad_slot1_partition_container: partition@174000 { - reg = <0x174000 DT_SIZE_K(192)>; /* 238 - 128 - 8 = 192 KB allocated */ + /* Remaining space in the slot 1. */ + cpurad_slot1_partition_container: partition@184000 { + reg = <0x184000 DT_SIZE_K(128)>; }; storage_partition: partition@1a4000 { diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_cpurad.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_cpurad.dtsi new file mode 100644 index 00000000000..c6532812542 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_cpurad.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* Use the whole TCM region for the remote firmware. */ +&cpurad_ram0 { + compatible = "mmio-sram"; + /delete-property/ reg; + reg = < 0x23000000 0x30000 >; + ranges = < 0x0 0x23000000 0x30000 >; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 2f2d29e7814..a5d4d7f0528 100644 --- a/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -7,7 +7,7 @@ #include "memory_map.dtsi" &cpuapp_data { - reg = <0x2f000000 0x40000>; + reg = <0x2f000000 0x39000>; }; secondary_app_partition: &cpuapp_slot1_partition {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf b/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf index 4191b264366..be2e7240bd9 100644 --- a/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf +++ b/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf @@ -5,4 +5,5 @@ # CONFIG_LOG=y -CONFIG_FLASH_BASE_ADDRESS=0x0 + +CONFIG_XIP=n diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay index b000cf21c5b..cec6d0fa545 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -5,21 +5,15 @@ */ #include "../../../boards/memory_map.dtsi" +#include "../../../boards/memory_map_ram_cpurad.dtsi" /{ chosen { zephyr,code-partition = &cpurad_loader_partition; - zephyr,sram = &cpurad_data_ram; + zephyr,sram = &cpurad_loader_ram; zephyr,loaded-fw-src = &cpurad_loaded_fw; zephyr,loaded-fw-dst = &cpurad_ram0; }; }; -&cpurad_ram0 { - compatible = "mmio-sram"; - /delete-property/ reg; - reg = < 0x23000000 0x20000 >; - ranges = < 0x0 0x23000000 0x20000 >; -}; - secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay index 8d1e0b76e08..b95426c647e 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay @@ -5,20 +5,14 @@ */ #include "../boards/memory_map.dtsi" +#include "../boards/memory_map_ram_cpurad.dtsi" /{ chosen { + zephyr,sram = &cpurad_loader_ram; zephyr,loaded-fw-src = &cpurad_loaded_fw_slot1; zephyr,loaded-fw-dst = &cpurad_ram0; - zephyr,sram = &cpurad_data_ram; }; }; -&cpurad_ram0 { - compatible = "mmio-sram"; - /delete-property/ reg; - reg = < 0x23000000 0x20000 >; - ranges = < 0x0 0x23000000 0x20000 >; -}; - secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay index 2eca1c59dec..dff53007200 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -5,18 +5,13 @@ */ #include "../../../boards/memory_map.dtsi" +#include "../../../boards/memory_map_ram_cpurad.dtsi" /{ chosen { - zephyr,code-partition = &cpurad_ram0; - zephyr,sram = &cpurad_data_ram; - fw-to-relocate = &cpurad_loaded_fw; + zephyr,code-partition = &cpurad_loaded_fw; + zephyr,sram = &cpurad_ram0; }; }; -&cpurad_ram0 { - compatible = "mmio-sram"; - /delete-property/ reg; - reg = < 0x23000000 0x20000 >; - ranges = < 0x0 0x23000000 0x20000 >; -}; +secondary_app_partition: &cpurad_loaded_fw_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf index 4191b264366..be2e7240bd9 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf @@ -5,4 +5,5 @@ # CONFIG_LOG=y -CONFIG_FLASH_BASE_ADDRESS=0x0 + +CONFIG_XIP=n diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay index 353c789aaad..efceab4c817 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay @@ -5,18 +5,13 @@ */ #include "../boards/memory_map.dtsi" +#include "../boards/memory_map_ram_cpurad.dtsi" /{ chosen { - fw-to-relocate = &cpurad_loaded_fw_slot1; + zephyr,code-partition = &cpurad_loaded_fw_slot1; + zephyr,sram = &cpurad_ram0; }; }; -&cpurad_ram0 { - compatible = "mmio-sram"; - /delete-property/ reg; - reg = < 0x23000000 0x20000 >; - ranges = < 0x0 0x23000000 0x20000 >; -}; - -secondary_app_partition: &cpurad_ram0 {}; +secondary_app_partition: &cpurad_loaded_fw_slot1 {}; From 593f9c01e47774ba3b104e0d53785926d3671d3b Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Thu, 27 Nov 2025 08:06:29 +0100 Subject: [PATCH 08/11] sysbuild: Adapt radio loader to support direct-xip in split slot mode Adapted the sysbuild configuration so the Radio Loader could support the MCUboot in the direct-xip in split slot mode. Adapted also the radio_loader sample to properly select the vector table pointer as in split mode each image has a MCUboot header which needs to be skipped. Jira: NCSDK-36461 Co-authored-by: Jan Zyczkowski Signed-off-by: Mateusz Kapala --- samples/nrf54h20/radio_loader/src/main.c | 2 +- sysbuild/Kconfig.mcuboot | 1 + sysbuild/radioloader.cmake | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/nrf54h20/radio_loader/src/main.c b/samples/nrf54h20/radio_loader/src/main.c index e1754b638c1..b726bac42ee 100644 --- a/samples/nrf54h20/radio_loader/src/main.c +++ b/samples/nrf54h20/radio_loader/src/main.c @@ -47,7 +47,7 @@ static int load_and_jump_to_firmware(void) memcpy((void *)LOADED_FW_RAM_ADDR, (void *)LOADED_FW_NVM_ADDR, LOADED_FW_NVM_SIZE); /* Extract reset handler from ARM Cortex-M vector table (entry 1) */ - uint32_t *vector_table = (uint32_t *)LOADED_FW_RAM_ADDR; + uint32_t *vector_table = (uint32_t *)(LOADED_FW_RAM_ADDR + CONFIG_ROM_START_OFFSET); typedef void reset_handler_t(void); reset_handler_t *reset_handler = (reset_handler_t *)(vector_table[1]); diff --git a/sysbuild/Kconfig.mcuboot b/sysbuild/Kconfig.mcuboot index 896d3706506..5e603a91660 100644 --- a/sysbuild/Kconfig.mcuboot +++ b/sysbuild/Kconfig.mcuboot @@ -135,6 +135,7 @@ config MCUBOOT_MIN_UPDATEABLE_IMAGES config MCUBOOT_MIN_ADDITIONAL_UPDATEABLE_IMAGES int default 1 if SECURE_BOOT_APPCORE + default 1 if NRF_RADIO_LOADER && !MCUBOOT_SIGN_MERGED_BINARY default 0 config MCUBOOT_UPDATEABLE_IMAGES diff --git a/sysbuild/radioloader.cmake b/sysbuild/radioloader.cmake index 47ea3a838c3..d0cb301e68c 100644 --- a/sysbuild/radioloader.cmake +++ b/sysbuild/radioloader.cmake @@ -19,6 +19,8 @@ if(SB_CONFIG_NRF_RADIO_LOADER) BOARD_REVISION ${BOARD_REVISION} ) + set_target_properties(radio_loader PROPERTIES + IMAGE_CONF_SCRIPT ${ZEPHYR_BASE}/share/sysbuild/image_configurations/MAIN_image_default.cmake) UpdateableImage_Add(APPLICATION radio_loader) # Note: Memory map configuration should be provided by the user project From f4034bd80c7bfddbee367948ce250f8c51b7d283 Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Fri, 28 Nov 2025 14:23:23 +0100 Subject: [PATCH 09/11] samples: Add configs for MCUboot in direct-xip in split slot mode Added configurations for the application with MCUboot in the direct-xip mode with split slots (each image has their slots independent from other images). Jira: NCSDK-36461 Co-authored-by: Jan Zyczkowski Signed-off-by: Mateusz Kapala --- .../boards/memory_map_ram_pm_cpurad.dtsi | 26 ++++ .../boards/memory_map_split_slot.dtsi | 135 ++++++++++++++++++ ...54h20dk_nrf54h20_cpuapp_split_slot.overlay | 13 ++ .../sysbuild/mcuboot_split_slot.conf | 8 ++ .../sysbuild/mcuboot_split_slot.overlay | 13 ++ ...54h20dk_nrf54h20_cpurad_split_slot.overlay | 19 +++ ...io_loader_secondary_app_split_slot.overlay | 18 +++ ...54h20dk_nrf54h20_cpurad_split_slot.overlay | 18 +++ ...emote_rad_secondary_app_split_slot.overlay | 18 +++ .../sysbuild_split_slot.conf | 20 +++ .../nrf54h20/idle_relocated_tcm/testcase.yaml | 10 +- 11 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_pm_cpurad.dtsi create mode 100644 samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi create mode 100644 samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp_split_slot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.conf create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay create mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild_split_slot.conf diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_pm_cpurad.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_pm_cpurad.dtsi new file mode 100644 index 00000000000..09e14db3acd --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_ram_pm_cpurad.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* Power Management relocates the key functions to TCM under the address + * from the pm_ramfunc DTS node. + * It is done at the zephyr/soc/nordic/nrf54h/CMakeLists.txt file. + * Theoretically it would not be necessary to relocate it if the whole code is in TCM. + * The changes in Zephyr would be required to allow it. + * As a workaround, relocate the pm_ramfunc to the end of the RAM block but before + * the MCUboot trailer. + */ +/delete-node/ &pm_ramfunc; + +/ { + soc { + /* cache control functions - must be executed from RAM */ + pm_ramfunc: cpurad_s2ram@2302df40 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2302df40 192>; + zephyr,memory-region = "PMLocalRamfunc"; + }; + }; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi new file mode 100644 index 00000000000..49001693bbe --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/{ + soc{ + /* Small piece of Global RAM for the radio loader to use during FW relocation. */ + cpurad_loader_ram: sram@2f039000 { + compatible = "mmio-sram"; + reg = < 0x2f039000 0x1000 >; + #address-cells = < 0x1 >; + #size-cells = < 0x1 >; + ranges = < 0x0 0x2f039000 0x1000 >; + }; + }; +}; + +&mram1x { + /delete-node/ partitions; + + /* Redefine the "partitions" DTS node. */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_boot_partition: boot_partition: partition@30000 { + reg = < 0x30000 0x10000 >; + label = "mcuboot"; + }; + + /* Image 0, slot 0 (primary slot) - Application code for cpuapp core. */ + slot0_partition: cpuapp_slot0_partition: partition@40000 { + reg = <0x40000 DT_SIZE_K(326)>; + }; + + /* Image 2, slot 0 (primary slot) - radio loader code for cpurad core. */ + slot4_partition: cpurad_slot0_partition: cpurad_loader_partition: + partition@92000 { + label = "cpurad_loader_partition"; + reg = <0x92000 DT_SIZE_K(16)>; + /* size: radio loader + 2KB trailer MCUboot + * (imgtool assumes that the swap mode is used always) + */ + }; + + /* Image 1, slot 0 (primary slot) - radio core application code + * relocated from MRAM to TCM for cpurad core. + */ + slot2_partition: cpurad_loaded_fw: partition@96000 { + label = "cpurad_loaded_fw"; + reg = <0x96000 (DT_SIZE_K(192))>; + /* size: application + 192B for s2ram + 2KB trailer MCUboot */ + }; + + cpuppr_code_partition: partition@e4000 { + reg = <0xe4000 DT_SIZE_K(64)>; + }; + + cpuflpr_code_partition: partition@f4000 { + reg = <0xf4000 DT_SIZE_K(48)>; + }; + + /* Image 0, slot 1 (secondary slot) - Application code for cpuapp core. */ + slot1_partition: cpuapp_slot1_partition: partition@100000 { + reg = <0x100000 DT_SIZE_K(326)>; + }; + + /* Image 2, slot 1 (secondary slot) - radio loader code for cpurad core. */ + slot5_partition: cpurad_slot1_partition: cpurad_loader_partition_slot1: + partition@152000 { + label = "cpurad_loader_partition_slot1"; + reg = <0x152000 DT_SIZE_K(16)>; + /* size: radio loader + 2KB trailer MCUboot + * (imgtool assumes that the swap mode is used always) + */ + }; + + /* Image 1, slot 1 (secondary slot) - radio core application code + * relocated from MRAM to TCM for cpurad core. + */ + slot3_partition: cpurad_loaded_fw_slot1: partition@156000 { + label = "cpurad_loaded_fw_slot1"; + reg = <0x156000 (DT_SIZE_K(192))>; + /* size: application + 192B for s2ram + 2KB trailer MCUboot */ + }; + + storage_partition: partition@1a4000 { + reg = <0x1a4000 DT_SIZE_K(40)>; + }; + + periphconf_partition: partition@1ae000 { + reg = <0x1ae000 DT_SIZE_K(8)>; + }; + + secondary_partition: partition@1b0000 { + reg = <0x1b0000 DT_SIZE_K(64)>; + }; + + secondary_periphconf_partition: partition@1c0000 { + reg = <0x1c0000 DT_SIZE_K(8)>; + }; + + /* NB: A gap has been left here for future partitions */ + + /* 0x1fd000 was chosen for secure_storage_partition such that + * there is no more space after secure_storage_partition. + */ + secure_storage_partition: partition@1fd000 { + compatible = "fixed-subpartitions"; + reg = <0x1fd000 DT_SIZE_K(12)>; + ranges = <0x0 0x1fd000 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_crypto_partition: partition@0 { + reg = <0x0 DT_SIZE_K(4)>; + }; + + cpurad_crypto_partition: partition@1000 { + reg = <0x1000 DT_SIZE_K(4)>; + }; + + cpuapp_its_partition: partition@2000 { + reg = <0x2000 DT_SIZE_K(2)>; + }; + + cpurad_its_partition: partition@2800 { + reg = <0x2800 DT_SIZE_K(2)>; + }; + }; + }; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp_split_slot.overlay new file mode 100644 index 00000000000..6ceb5f8ed83 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp_split_slot.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "memory_map_split_slot.dtsi" + +&cpuapp_data { + reg = <0x2f000000 0x39000>; +}; + +secondary_app_partition: &cpuapp_slot1_partition {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.conf new file mode 100644 index 00000000000..f1caef92309 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_NRF_SECURITY=y +CONFIG_MULTITHREADING=y diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.overlay new file mode 100644 index 00000000000..0cc252a66dd --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/mcuboot_split_slot.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../boards/memory_map_split_slot.dtsi" + +/ { + chosen { + zephyr,code-partition = &boot_partition; + }; +}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay new file mode 100644 index 00000000000..39c4f077ad9 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../../../boards/memory_map_split_slot.dtsi" +#include "../../../boards/memory_map_ram_cpurad.dtsi" + +/{ + chosen { + zephyr,code-partition = &cpurad_loader_partition; + zephyr,sram = &cpurad_loader_ram; + zephyr,loaded-fw-src = &cpurad_loaded_fw; + zephyr,loaded-fw-dst = &cpurad_ram0; + }; +}; + +secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay new file mode 100644 index 00000000000..531ecb018f4 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../boards/memory_map_split_slot.dtsi" +#include "../boards/memory_map_ram_cpurad.dtsi" + +/{ + chosen { + zephyr,sram = &cpurad_loader_ram; + zephyr,loaded-fw-src = &cpurad_loaded_fw_slot1; + zephyr,loaded-fw-dst = &cpurad_ram0; + }; +}; + +secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay new file mode 100644 index 00000000000..d63de229653 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + + #include "../../../boards/memory_map_split_slot.dtsi" + #include "../../../boards/memory_map_ram_cpurad.dtsi" + #include "../../../boards/memory_map_ram_pm_cpurad.dtsi" + +/{ + chosen { + zephyr,code-partition = &cpurad_loaded_fw; + zephyr,sram = &cpurad_ram0; + }; +}; + +secondary_app_partition: &cpurad_loaded_fw_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay new file mode 100644 index 00000000000..5cf730f7598 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../boards/memory_map_split_slot.dtsi" +#include "../boards/memory_map_ram_cpurad.dtsi" +#include "../boards/memory_map_ram_pm_cpurad.dtsi" + +/{ + chosen { + zephyr,code-partition = &cpurad_loaded_fw_slot1; + zephyr,sram = &cpurad_ram0; + }; +}; + +secondary_app_partition: &cpurad_loaded_fw_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild_split_slot.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild_split_slot.conf new file mode 100644 index 00000000000..5520770828d --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild_split_slot.conf @@ -0,0 +1,20 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# This automatically adds the radio_loader application to the build +SB_CONFIG_NRF_RADIO_LOADER=y +SB_CONFIG_NETCORE_CUSTOM_RADIO=y + +SB_CONFIG_BOOTLOADER_MCUBOOT=y +SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP=y +SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519=y +SB_CONFIG_BOOT_SIGNATURE_TYPE_PURE=y + +# Disable merging of slots -> use separate slots for each image +SB_CONFIG_MCUBOOT_SIGN_MERGED_BINARY=n + +# Enable manifest-based updates +SB_CONFIG_MCUBOOT_MANIFEST_UPDATES=y diff --git a/samples/nrf54h20/idle_relocated_tcm/testcase.yaml b/samples/nrf54h20/idle_relocated_tcm/testcase.yaml index 702e4dd2e27..76d90466f7c 100644 --- a/samples/nrf54h20/idle_relocated_tcm/testcase.yaml +++ b/samples/nrf54h20/idle_relocated_tcm/testcase.yaml @@ -12,9 +12,17 @@ common: - "Multicore idle test iteration 1" tests: - benchmarks.multicore.idle_relocated_tcm.nrf54h20dk_cpuapp_cpurad: + benchmarks.multicore.idle_relocated_tcm.nrf54h20dk_cpuapp_cpurad.direct_xip.merged_slot: harness: console platform_allow: - nrf54h20dk/nrf54h20/cpuapp integration_platforms: - nrf54h20dk/nrf54h20/cpuapp + benchmarks.multicore.idle_relocated_tcm.nrf54h20dk_cpuapp_cpurad.direct_xip.split_slot: + harness: console + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp + extra_args: + - FILE_SUFFIX=split_slot From 3a1ac2e2bae251d7381a4eb7eac666077b0a9a3d Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Fri, 28 Nov 2025 15:38:28 +0100 Subject: [PATCH 10/11] samples: idle_relocated_tcm: Add log with code partition addr to remote Added log with zephyr,code-partition DTS node address to determine from which slot the image has been loaded. Jira: NCSDK-36461 Signed-off-by: Mateusz Kapala --- samples/nrf54h20/idle_relocated_tcm/remote/src/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c b/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c index d8b4d982081..d60c1757151 100644 --- a/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c +++ b/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c @@ -9,6 +9,9 @@ LOG_MODULE_REGISTER(idle); +#define CODE_PARTITION_NODE DT_CHOSEN(zephyr_code_partition) +#define CODE_PARTITION_START_ADDR DT_FIXED_PARTITION_ADDR(CODE_PARTITION_NODE) + int main(void) { unsigned int cnt = 0; @@ -16,6 +19,8 @@ int main(void) __asm__ volatile("adr %0, ." : "=r"(pc)); LOG_INF("Multicore idle test on %s", CONFIG_BOARD_TARGET); + LOG_INF("Original code partition start address: 0x%lx\n", + (unsigned long)CODE_PARTITION_START_ADDR); LOG_INF("Current PC (program counter) address: 0x%lx\n", (unsigned long)pc); /* using __TIME__ ensure that a new binary will be built on every From 1c7bc781b83a9e534a731fd0974cf2f2092e143e Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Mon, 1 Dec 2025 13:59:22 +0100 Subject: [PATCH 11/11] [wip] samples: idle_relocated_tcm: Simplify configurations Changed DTS node selection in radio_loader. Simplified configurations needed to run from TCM. Jira: NCSDK-36457 Signed-off-by: Mateusz Kapala --- .../idle_relocated_tcm/boards/memory_map.dtsi | 6 +- .../boards/memory_map_split_slot.dtsi | 4 +- ...ndary_app.overlay => radio_loader.overlay} | 3 +- .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 19 ---- ...54h20dk_nrf54h20_cpurad_split_slot.overlay | 19 ---- .../sysbuild/radio_loader/prj.conf | 94 ------------------- ...verlay => radio_loader_split_slot.overlay} | 3 +- ...condary_app.overlay => remote_rad.overlay} | 2 +- .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 17 ---- ...54h20dk_nrf54h20_cpurad_split_slot.overlay | 18 ---- .../sysbuild/remote_rad/prj.conf | 9 -- ....overlay => remote_rad_split_slot.overlay} | 2 +- samples/nrf54h20/radio_loader/src/main.c | 84 ++++++++++++----- 13 files changed, 71 insertions(+), 209 deletions(-) rename samples/nrf54h20/idle_relocated_tcm/sysbuild/{radio_loader_secondary_app.overlay => radio_loader.overlay} (78%) delete mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay delete mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay delete mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf rename samples/nrf54h20/idle_relocated_tcm/sysbuild/{radio_loader_secondary_app_split_slot.overlay => radio_loader_split_slot.overlay} (78%) rename samples/nrf54h20/idle_relocated_tcm/sysbuild/{remote_rad_secondary_app.overlay => remote_rad.overlay} (85%) delete mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay delete mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay delete mode 100644 samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf rename samples/nrf54h20/idle_relocated_tcm/sysbuild/{remote_rad_secondary_app_split_slot.overlay => remote_rad_split_slot.overlay} (87%) diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi index b40c11046b5..96017ba2d0b 100644 --- a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi @@ -49,7 +49,7 @@ }; /* Radio core application code relocated from MRAM to TCM for cpurad core. */ - cpurad_loaded_fw: partition@94000 { + cpurad_slot2_partition: cpurad_loaded_fw: partition@94000 { label = "cpurad_loaded_fw"; reg = <0x94000 DT_SIZE_K(192)>; }; @@ -78,13 +78,13 @@ }; /* Radio core firmware loader code for cpurad core. */ - cpurad_loader_partition_slot1: cpurad_slot1_partition: partition@152000 { + cpurad_slot1_partition: cpurad_loader_partition_slot1: partition@152000 { label = "cpurad_loader_partition_slot1"; reg = <0x152000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */ }; /* Radio core application code relocated from MRAM to TCM for cpurad core. */ - cpurad_loaded_fw_slot1: partition@154000 { + cpurad_slot3_partition: cpurad_loaded_fw_slot1: partition@154000 { label = "cpurad_loaded_fw_slot1"; reg = <0x154000 DT_SIZE_K(192)>; }; diff --git a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi index 49001693bbe..8706b150c47 100644 --- a/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map_split_slot.dtsi @@ -49,7 +49,7 @@ /* Image 1, slot 0 (primary slot) - radio core application code * relocated from MRAM to TCM for cpurad core. */ - slot2_partition: cpurad_loaded_fw: partition@96000 { + slot2_partition: cpurad_slot2_partition: cpurad_loaded_fw: partition@96000 { label = "cpurad_loaded_fw"; reg = <0x96000 (DT_SIZE_K(192))>; /* size: application + 192B for s2ram + 2KB trailer MCUboot */ @@ -81,7 +81,7 @@ /* Image 1, slot 1 (secondary slot) - radio core application code * relocated from MRAM to TCM for cpurad core. */ - slot3_partition: cpurad_loaded_fw_slot1: partition@156000 { + slot3_partition: cpurad_slot3_partition: cpurad_loaded_fw_slot1: partition@156000 { label = "cpurad_loaded_fw_slot1"; reg = <0x156000 (DT_SIZE_K(192))>; /* size: application + 192B for s2ram + 2KB trailer MCUboot */ diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader.overlay similarity index 78% rename from samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay rename to samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader.overlay index b95426c647e..61b7dc0f97c 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader.overlay @@ -9,9 +9,8 @@ /{ chosen { + zephyr,code-partition = &cpurad_loader_partition; zephyr,sram = &cpurad_loader_ram; - zephyr,loaded-fw-src = &cpurad_loaded_fw_slot1; - zephyr,loaded-fw-dst = &cpurad_ram0; }; }; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay deleted file mode 100644 index cec6d0fa545..00000000000 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include "../../../boards/memory_map.dtsi" -#include "../../../boards/memory_map_ram_cpurad.dtsi" - -/{ - chosen { - zephyr,code-partition = &cpurad_loader_partition; - zephyr,sram = &cpurad_loader_ram; - zephyr,loaded-fw-src = &cpurad_loaded_fw; - zephyr,loaded-fw-dst = &cpurad_ram0; - }; -}; - -secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay deleted file mode 100644 index 39c4f077ad9..00000000000 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include "../../../boards/memory_map_split_slot.dtsi" -#include "../../../boards/memory_map_ram_cpurad.dtsi" - -/{ - chosen { - zephyr,code-partition = &cpurad_loader_partition; - zephyr,sram = &cpurad_loader_ram; - zephyr,loaded-fw-src = &cpurad_loaded_fw; - zephyr,loaded-fw-dst = &cpurad_ram0; - }; -}; - -secondary_app_partition: &cpurad_loader_partition_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf deleted file mode 100644 index 6f57c25fea8..00000000000 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/prj.conf +++ /dev/null @@ -1,94 +0,0 @@ -# -# Copyright (c) 2025 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause -# - -# ============================================================================== -# Optimized minimal configuration for radio_loader -# ============================================================================== -# This loader only runs SYS_INIT(load_and_jump_to_firmware, EARLY, 0) which: -# 1. Copies firmware from MRAM to TCM using memcpy() -# 2. Jumps to the loaded firmware's reset handler -# No Zephyr services, threading, or drivers are needed. -# -# Memory footprint target: < 4 KB - -# ============================================================================== -# Power Management -# ============================================================================== -CONFIG_PM=n -CONFIG_PM_DEVICE=n - -# ============================================================================== -# Kernel - Threading Disabled -# ============================================================================== -# We never reach main() or start the scheduler, so disable all threading -CONFIG_MULTITHREADING=n -CONFIG_MAIN_STACK_SIZE=512 -CONFIG_THREAD_STACK_INFO=n - -# Disable kernel features that require threading/scheduler -CONFIG_EVENTS=n -CONFIG_POLL=n -CONFIG_TIMESLICING=n - -# ============================================================================== -# Console, Debug, and Logging -# ============================================================================== -# No console output needed - loader jumps immediately to firmware -CONFIG_CONSOLE=n -CONFIG_UART_CONSOLE=n -CONFIG_SERIAL=n -CONFIG_PRINTK=n -CONFIG_EARLY_CONSOLE=n -CONFIG_LOG=n - -# Banners and debug features -CONFIG_NCS_BOOT_BANNER=n -CONFIG_BOOT_BANNER=n -CONFIG_ERRNO=n - -# ============================================================================== -# Device Drivers -# ============================================================================== -# No peripheral drivers needed - we only use memcpy and jump -CONFIG_GPIO=n -CONFIG_PINCTRL=n -CONFIG_I2C=n -CONFIG_SPI=n -CONFIG_WATCHDOG=n - -# ============================================================================== -# Interrupt Management -# ============================================================================== -CONFIG_DYNAMIC_INTERRUPTS=n -CONFIG_IRQ_OFFLOAD=n -CONFIG_GEN_IRQ_VECTOR_TABLE=n -CONFIG_GEN_ISR_TABLES=n -CONFIG_GEN_SW_ISR_TABLE=n - -# ============================================================================== -# Hardware Protection -# ============================================================================== -CONFIG_HW_STACK_PROTECTION=n -CONFIG_ARM_MPU=n - -# ============================================================================== -# Security and Crypto -# ============================================================================== -# No crypto needed for simple memory copy operation -CONFIG_NRF_SECURITY=n -CONFIG_MBEDTLS_PSA_CRYPTO_C=n -CONFIG_PSA_CRYPTO_DRIVER_OBERON=n -CONFIG_PSA_CRYPTO=n -CONFIG_PSA_SSF_CRYPTO_CLIENT=n - -# ============================================================================== -# Memory Optimization -# ============================================================================== -CONFIG_HEAP_MEM_POOL_SIZE=0 -CONFIG_SYS_HEAP_RUNTIME_STATS=n - -# Use nano printf for minimal footprint (only used if PRINTK somehow gets enabled) -CONFIG_CBPRINTF_NANO=y diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_split_slot.overlay similarity index 78% rename from samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay rename to samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_split_slot.overlay index 531ecb018f4..071340f4bae 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app_split_slot.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_split_slot.overlay @@ -9,9 +9,8 @@ /{ chosen { + zephyr,code-partition = &cpurad_loader_partition; zephyr,sram = &cpurad_loader_ram; - zephyr,loaded-fw-src = &cpurad_loaded_fw_slot1; - zephyr,loaded-fw-dst = &cpurad_ram0; }; }; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad.overlay similarity index 85% rename from samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay rename to samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad.overlay index efceab4c817..6ae63d993a6 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad.overlay @@ -9,7 +9,7 @@ /{ chosen { - zephyr,code-partition = &cpurad_loaded_fw_slot1; + zephyr,code-partition = &cpurad_loaded_fw; zephyr,sram = &cpurad_ram0; }; }; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay deleted file mode 100644 index dff53007200..00000000000 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include "../../../boards/memory_map.dtsi" -#include "../../../boards/memory_map_ram_cpurad.dtsi" - -/{ - chosen { - zephyr,code-partition = &cpurad_loaded_fw; - zephyr,sram = &cpurad_ram0; - }; -}; - -secondary_app_partition: &cpurad_loaded_fw_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay deleted file mode 100644 index d63de229653..00000000000 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad_split_slot.overlay +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - - #include "../../../boards/memory_map_split_slot.dtsi" - #include "../../../boards/memory_map_ram_cpurad.dtsi" - #include "../../../boards/memory_map_ram_pm_cpurad.dtsi" - -/{ - chosen { - zephyr,code-partition = &cpurad_loaded_fw; - zephyr,sram = &cpurad_ram0; - }; -}; - -secondary_app_partition: &cpurad_loaded_fw_slot1 {}; diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf deleted file mode 100644 index be2e7240bd9..00000000000 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf +++ /dev/null @@ -1,9 +0,0 @@ -# -# Copyright (c) 2025 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause -# - -CONFIG_LOG=y - -CONFIG_XIP=n diff --git a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_split_slot.overlay similarity index 87% rename from samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay rename to samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_split_slot.overlay index 5cf730f7598..9df3124fe92 100644 --- a/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app_split_slot.overlay +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_split_slot.overlay @@ -10,7 +10,7 @@ /{ chosen { - zephyr,code-partition = &cpurad_loaded_fw_slot1; + zephyr,code-partition = &cpurad_loaded_fw; zephyr,sram = &cpurad_ram0; }; }; diff --git a/samples/nrf54h20/radio_loader/src/main.c b/samples/nrf54h20/radio_loader/src/main.c index b726bac42ee..a898161a47b 100644 --- a/samples/nrf54h20/radio_loader/src/main.c +++ b/samples/nrf54h20/radio_loader/src/main.c @@ -6,29 +6,50 @@ #include -/* The loader uses devicetree chosen nodes to specify source - * and destination memory regions: - * - zephyr,loaded-fw-src: Source partition in NVM - * - zephyr,loaded-fw-dst: Destination region in RAM - */ +#define FIXED_PARTITION_ADDRESS(label) \ + (DT_REG_ADDR(DT_NODELABEL(label)) + \ + DT_REG_ADDR(COND_CODE_1(DT_FIXED_SUBPARTITION_EXISTS(DT_NODELABEL(label)), \ + (DT_GPARENT(DT_PARENT(DT_NODELABEL(label)))), \ + (DT_GPARENT(DT_NODELABEL(label)))))) + +#define FIXED_PARTITION_SIZE(label) DT_REG_SIZE(DT_NODELABEL(label)) + +#ifdef CONFIG_USE_DT_CODE_PARTITION +#define FLASH_LOAD_OFFSET DT_REG_ADDR(DT_CHOSEN(zephyr_code_partition)) +#elif defined(CONFIG_FLASH_LOAD_OFFSET) +#define FLASH_LOAD_OFFSET CONFIG_FLASH_LOAD_OFFSET +#endif + +#define PARTITION_IS_RUNNING_APP_PARTITION(label) \ + (DT_REG_ADDR(DT_NODELABEL(label)) <= FLASH_LOAD_OFFSET && \ + DT_REG_ADDR(DT_NODELABEL(label)) + DT_REG_SIZE(DT_NODELABEL(label)) > FLASH_LOAD_OFFSET) + +/* Used to determine the running slot of the radio loader. */ +#define CPURAD_LOADER_PRIMARY_SLOT cpurad_slot0_partition +#define CPURAD_LOADER_SECONDARY_SLOT cpurad_slot1_partition + +/* Used to determine the loaded firmware source address from NVM and size. */ +#define CPURAD_LOADED_FW_PRIMARY_SLOT cpurad_slot2_partition +#define CPURAD_LOADED_FW_SECONDARY_SLOT cpurad_slot3_partition -#define LOADED_FW_NVM_NODE DT_CHOSEN(zephyr_loaded_fw_src) -#define LOADED_FW_NVM_PARTITION_NODE DT_PARENT(DT_PARENT(LOADED_FW_NVM_NODE)) -#define LOADED_FW_NVM_ADDR (DT_REG_ADDR(LOADED_FW_NVM_NODE) + \ - DT_REG_ADDR(LOADED_FW_NVM_PARTITION_NODE)) -#define LOADED_FW_NVM_SIZE DT_REG_SIZE(LOADED_FW_NVM_NODE) +/* Used to determine the running slot of the radio core. */ +#define CPURAD_RUNNING_SLOT cpurad_ram0 +#define CPURAD_RUNNING_SLOT_NODE DT_NODELABEL(CPURAD_RUNNING_SLOT) +#define CPURAD_RUNNING_SLOT_ADDR DT_REG_ADDR(CPURAD_RUNNING_SLOT_NODE) +#define CPURAD_RUNNING_SLOT_SIZE DT_REG_SIZE(CPURAD_RUNNING_SLOT_NODE) -#define LOADED_FW_RAM_NODE DT_CHOSEN(zephyr_loaded_fw_dst) -#define LOADED_FW_RAM_ADDR DT_REG_ADDR(LOADED_FW_RAM_NODE) -#define LOADED_FW_RAM_SIZE DT_REG_SIZE(LOADED_FW_RAM_NODE) +BUILD_ASSERT(DT_NODE_EXISTS(DT_NODELABEL(CPURAD_LOADER_PRIMARY_SLOT)), + "Missing nodelabel: cpurad_slot0_partition"); +BUILD_ASSERT(DT_NODE_EXISTS(DT_NODELABEL(CPURAD_LOADER_SECONDARY_SLOT)), + "Missing nodelabel: cpurad_slot1_partition"); -/* Verify devicetree configuration at build time */ -BUILD_ASSERT(DT_NODE_EXISTS(DT_CHOSEN(zephyr_loaded_fw_src)), - "Missing chosen node: zephyr,loaded-fw-src"); -BUILD_ASSERT(DT_NODE_EXISTS(DT_CHOSEN(zephyr_loaded_fw_dst)), - "Missing chosen node: zephyr,loaded-fw-dst"); -BUILD_ASSERT(LOADED_FW_NVM_SIZE <= LOADED_FW_RAM_SIZE, - "Firmware size exceeds available TCM RAM"); +BUILD_ASSERT(DT_NODE_EXISTS(DT_NODELABEL(CPURAD_LOADED_FW_PRIMARY_SLOT)), + "Missing nodelabel: cpurad_slot2_partition"); +BUILD_ASSERT(DT_NODE_EXISTS(DT_NODELABEL(CPURAD_LOADED_FW_SECONDARY_SLOT)), + "Missing nodelabel: cpurad_slot3_partition"); + +BUILD_ASSERT(DT_NODE_EXISTS(DT_NODELABEL(CPURAD_RUNNING_SLOT)), + "Missing nodelabel: cpurad_ram0"); /** * @brief Copy firmware from MRAM to TCM and jump to it @@ -43,11 +64,30 @@ BUILD_ASSERT(LOADED_FW_NVM_SIZE <= LOADED_FW_RAM_SIZE, */ static int load_and_jump_to_firmware(void) { + /* Get the loaded firmware source address from NVM and size */ + void *loaded_fw_nvm_addr = NULL; + size_t loaded_fw_nvm_size = 0; + + /* Get the loaded firmware destination address from RAM and size */ + void *loaded_fw_ram_addr = (void *)(CPURAD_RUNNING_SLOT_ADDR); + size_t loaded_fw_ram_size = (size_t)(CPURAD_RUNNING_SLOT_SIZE); + + if (PARTITION_IS_RUNNING_APP_PARTITION(CPURAD_LOADER_PRIMARY_SLOT)) { + loaded_fw_nvm_addr = (void *)(FIXED_PARTITION_ADDRESS(CPURAD_LOADED_FW_PRIMARY_SLOT)); + loaded_fw_nvm_size = (size_t)(FIXED_PARTITION_SIZE(CPURAD_LOADED_FW_PRIMARY_SLOT)); + } else { + loaded_fw_nvm_addr = (void *)(FIXED_PARTITION_ADDRESS(CPURAD_LOADED_FW_SECONDARY_SLOT)); + loaded_fw_nvm_size = (size_t)(FIXED_PARTITION_SIZE(CPURAD_LOADED_FW_SECONDARY_SLOT)); + } + + __ASSERT(loaded_fw_nvm_size <= loaded_fw_ram_size, "Loaded firmware NVM size exceeds available TCM RAM"); + ARG_UNUSED(loaded_fw_ram_size); + /* Copy firmware from MRAM to TCM */ - memcpy((void *)LOADED_FW_RAM_ADDR, (void *)LOADED_FW_NVM_ADDR, LOADED_FW_NVM_SIZE); + memcpy(loaded_fw_ram_addr, loaded_fw_nvm_addr, loaded_fw_nvm_size); /* Extract reset handler from ARM Cortex-M vector table (entry 1) */ - uint32_t *vector_table = (uint32_t *)(LOADED_FW_RAM_ADDR + CONFIG_ROM_START_OFFSET); + uint32_t *vector_table = (uint32_t *)((uint8_t *)loaded_fw_ram_addr + CONFIG_ROM_START_OFFSET); typedef void reset_handler_t(void); reset_handler_t *reset_handler = (reset_handler_t *)(vector_table[1]);