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/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index b84cef0a9fc..9255cfc7ba2 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -33,6 +33,11 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) 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) @@ -56,6 +61,10 @@ 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() @@ -73,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/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}) diff --git a/cmake/sysbuild/sign_nrf54h20.cmake b/cmake/sysbuild/sign_nrf54h20.cmake index 6946ed0c785..8ace02403e8 100644 --- a/cmake/sysbuild/sign_nrf54h20.cmake +++ b/cmake/sysbuild/sign_nrf54h20.cmake @@ -26,6 +26,7 @@ function(check_merged_slot_boundaries merged_partition images) 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_partition_addr(code_addr PATH "${code_flash}" TARGET ${image} REQUIRED ABSOLUTE) dt_reg_size(code_size TARGET ${image} PATH ${code_flash}) 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.dtsi b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi new file mode 100644 index 00000000000..b40c11046b5 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/boards/memory_map.dtsi @@ -0,0 +1,142 @@ +/* + * 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): 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) */ + }; + + /* 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(192)>; + }; + + /* Remaining space in the slot 0. */ + cpurad_slot0_partition_container: partition@c4000 { + reg = <0xc4000 DT_SIZE_K(128)>; + }; + + 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): 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) */ + }; + + /* 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(192)>; + }; + + /* Remaining space in the slot 1. */ + cpurad_slot1_partition_container: partition@184000 { + reg = <0x184000 DT_SIZE_K(128)>; + }; + + 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/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/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.overlay b/samples/nrf54h20/idle_relocated_tcm/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..a5d4d7f0528 --- /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.dtsi" + +&cpuapp_data { + reg = <0x2f000000 0x39000>; +}; + +secondary_app_partition: &cpuapp_slot1_partition {}; 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/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..be2e7240bd9 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/remote/prj.conf @@ -0,0 +1,9 @@ +# +# 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/remote/src/main.c b/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c new file mode 100644 index 00000000000..d60c1757151 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/remote/src/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include + +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; + uintptr_t pc; + + __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 + * 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..9312764c429 --- /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.dtsi" + +/ { + chosen { + zephyr,code-partition = &boot_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.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..cec6d0fa545 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,19 @@ +/* + * 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 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/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..b95426c647e --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/radio_loader_secondary_app.overlay @@ -0,0 +1,18 @@ +/* + * 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,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/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.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..dff53007200 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,17 @@ +/* + * 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 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/prj.conf b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf new file mode 100644 index 00000000000..be2e7240bd9 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad/prj.conf @@ -0,0 +1,9 @@ +# +# 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.overlay b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay new file mode 100644 index 00000000000..efceab4c817 --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/sysbuild/remote_rad_secondary_app.overlay @@ -0,0 +1,17 @@ +/* + * 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_slot1; + 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 new file mode 100644 index 00000000000..76d90466f7c --- /dev/null +++ b/samples/nrf54h20/idle_relocated_tcm/testcase.yaml @@ -0,0 +1,28 @@ +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.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 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..b726bac42ee --- /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 + CONFIG_ROM_START_OFFSET); + 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/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..c3608609326 --- /dev/null +++ b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -0,0 +1,16 @@ +# Nordic Semiconductor nRF54H20 Radio MCU + +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +if SOC_NRF54H20_CPURAD + +DT_CHOSEN_Z_CODE = zephyr,code-partition +DT_CHOSEN_Z_SRAM = zephyr,sram + +config BUILD_OUTPUT_ADJUST_LMA + 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 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.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/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..d0cb301e68c --- /dev/null +++ b/sysbuild/radioloader.cmake @@ -0,0 +1,30 @@ +# +# 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} + ) + + 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 + # in: sysbuild/radio_loader/boards/.overlay + # This overlay should define partitions and chosen nodes for the loader + +endif()