Platform: RP2350: Add RP2350 porting

Change-Id: I8359f2a0ccea6a5afade57fc651aa90dae678307
Signed-off-by: William Vinnicombe <william.vinnicombe@raspberrypi.com>
diff --git a/docs/contributing/maintainers.rst b/docs/contributing/maintainers.rst
index 2f62afb..65d49e4 100644
--- a/docs/contributing/maintainers.rst
+++ b/docs/contributing/maintainers.rst
@@ -183,6 +183,13 @@
     :email: `Jidong.Mei@armchina.com <Jidong.Mei@armchina.com>`__
     :github: `JidongMei <https://github.com/JidongMei>`__
 
+Raspberry Pi Platform:
+~~~~~~~~~~~~~~~~~~~~~~
+
+William Vinnicombe
+    :email: `William.Vinnicombe@raspberrypi.com <william.vinnicombe@raspberrypi.com>`__
+    :github: `Raspberry Pi <https://github.com/raspberrypi>`__
+
 =============
 
 .. _Project Maintenance Process: https://trusted-firmware-docs.readthedocs.io/en/latest/generic_processes/project_maintenance_process.html
diff --git a/docs/platform/index.rst b/docs/platform/index.rst
index 0aeca26..ada5921 100644
--- a/docs/platform/index.rst
+++ b/docs/platform/index.rst
@@ -14,8 +14,9 @@
     Nordic <nordic_nrf/index>
     Nuvoton <nuvoton/index>
     NXP <nxp/index>
+    Raspberry Pi <rpi/index>
     STMICROELECTRONICS <stm/index>
 
 --------------
 
-*Copyright (c) 2020-2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2020-2024, Arm Limited. All rights reserved.*
diff --git a/docs/platform/rpi/index.rst b/docs/platform/rpi/index.rst
new file mode 100644
index 0000000..6ad40a6
--- /dev/null
+++ b/docs/platform/rpi/index.rst
@@ -0,0 +1,14 @@
+######################
+Raspberry Pi platforms
+######################
+
+.. toctree::
+    :maxdepth: 1
+    :titlesonly:
+
+    RP2350 <rp2350/readme.rst>
+
+--------------
+
+ *SPDX-License-Identifier: BSD-3-Clause*
+ *SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors*
diff --git a/docs/platform/rpi/rp2350/readme.rst b/docs/platform/rpi/rp2350/readme.rst
new file mode 100644
index 0000000..176aba2
--- /dev/null
+++ b/docs/platform/rpi/rp2350/readme.rst
@@ -0,0 +1,139 @@
+RP2350
+======
+
+Introduction
+------------
+
+RP2350 features a dual-core Arm Cortex-M33 processor with 520 kiB on-chip SRAM,
+support for up to 16MB of off-chip flash and a wide range of flexible I/O option
+including I2C, SPI, and - uniquely - Programmable I/O (PIO). With its security
+features RP2350 offers significant enhancements over RP2040.
+
+This platform port supports TF-M regression tests (Secure and Non-secure)
+with Isolation Level 1 and 2.
+
+.. note::
+
+   Only GNU toolchain is supported.
+
+Building TF-M
+-------------
+
+Follow the instructions in :doc:`Building instructions </building/tfm_build_instruction>`.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Build instructions with platform name: rpi/rp2350
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+``-DTFM_PLATFORM=rpi/rp2350``
+
+.. note::
+
+   This platform port relies on
+   `Raspberry Pi Pico SDK <https://github.com/raspberrypi/pico-sdk>`__
+   Make sure it is either cloned locally or available to download during build.
+   SDK version used for testing: SDK 2.0.0 release
+
+.. note::
+
+   Building the default platform configuration requires the board to be
+   provisioned. For this the provision bundle needs to be built and run on the
+   board with ``-DPLATFORM_DEFAULT_PROVISIONING=OFF``. The binary must be
+   placed in flash at the address defined by ``PROVISIONING_BUNDLE_START``. One
+   way to do this is to generate a .uf2 file containing the bundle at the start
+   address and copy it to the board. There is an example in the provided
+   pico_uf2.sh script and in the description below.
+
+   If ``-DPLATFORM_DEFAULT_PROVISIONING=OFF`` and
+   ``-DTFM_DUMMY_PROVISIONING=ON`` then the keys in the
+   ``tf-m/platform/ext/common/provisioning_bundle/provisioning_config.cmake``
+   and the default MCUBoot signing keys will be used for provisioning.
+
+   If ``-DPLATFORM_DEFAULT_PROVISIONING=OFF`` and
+   ``-DTFM_DUMMY_PROVISIONING=OFF`` are set then unique values can be used for
+   provisioning. The keys and seeds can be changed by passing the new values to
+   the build command, or by setting the ``-DPROVISIONING_KEYS_CONFIG`` flag to a
+   .cmake file that contains the keys. An example config cmake file can be seen
+   at
+   ``tf-m/platform/ext/common/provisioning_bundle/provisioning_config.cmake``.
+   Otherwise new random values are going to be generated and used. For the image
+   signing the ${MCUBOOT_KEY_S} and ${MCUBOOT_KEY_NS} will be used. These
+   variables should point to .pem files that contain the code signing private
+   keys. The public keys are going to be generated from these private keys and
+   will be used for provisioning. The hash of the public key is going to be
+   written into the ``provisioning_data.c`` automatically.
+
+   If ``-DMCUBOOT_GENERATE_SIGNING_KEYPAIR=ON`` is set then a new mcuboot
+   signing public and private keypair is going to be generated and it's going to
+   be used to sign the S and NS binaries.
+
+   The new generated keypair can be found in the ``<build dir>/bin`` folder or
+   in the ``<install directory>/image_signing/keys`` after installation.
+   The generated provisioning_data.c file can be found at
+   ``<build directory>/platform/target/provisioning/provisioning_data.c``
+
+.. note::
+
+   The provisioning bundle generation depends on pyelftools that's have to be
+   installed::
+
+    pip3 install pyelftools
+
+Example build instructions for regression tests with dummy keys:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Building Secure side with provisioning bundle:
+
+.. note::
+
+   Add -DTFM_MULTI_CORE_TOPOLOGY=ON to the above for multicore support
+
+
+.. code-block:: bash
+
+     cmake -S <TF-M tests source dir>/tests_reg/spe \
+     -B <TF-M tests source dir>/tests_reg/spe/build_rpi_myns_single \
+     -DTFM_PLATFORM=rpi/rp2350 \
+     -DTFM_TOOLCHAIN_FILE=<TF-M source dir>/toolchain_GNUARM.cmake \
+     -DCONFIG_TFM_SOURCE_PATH=<TF-M source dir> \
+     -DTFM_PROFILE=profile_medium -DPLATFORM_DEFAULT_PROVISIONING=OFF \
+     -DTEST_S=ON -DTEST_NS=ON
+
+.. code-block:: bash
+
+     cmake --build <TF-M tests source dir>/tests_reg/spe/build_rpi_myns_single \
+     -- -j8 install
+
+
+Building Non-Secure side:
+
+.. code-block:: bash
+
+     cmake -S <TF-M tests source dir>/tests_reg \
+     -B <TF-M tests source dir>/tests_reg/build_rpi_myns_single \
+     -DCONFIG_SPE_PATH=<TF-M tests source dir>/tests_reg/spe/build_rpi_myns_single/api_ns \
+     -DTFM_TOOLCHAIN_FILE=<TF-M tests source dir>/tests_reg/spe/build_rpi_myns_single/api_ns/cmake/toolchain_ns_GNUARM.cmake
+     cmake --build <TF-M tests source dir>/tests_reg/build_rpi_myns_single -- -j8
+
+Binaries need to be converted with a small script pico_uf2.sh
+It uses uf2conv.py from here:
+https://github.com/microsoft/uf2/blob/master/utils/uf2conv.py
+It depends on:
+https://github.com/microsoft/uf2/blob/master/utils/uf2families.json
+The tool takes the combined and signed S and NS images in .bin format, and
+outputs .uf2. It also generates the .uf2 for the bootloader (bl2.uf2) and the
+provisioning bundle.
+
+.. code-block:: bash
+
+     pico_uf2.sh <TF-M tests source dir> build_rpi_myns_single
+
+Then just copy the bl2.uf and tfm_s_ns_signed.bin.uf2 files to the board. It
+will run the BL2, S and NS tests and print the results to the UART (Baudrate
+115200).
+If the board needs provisioning, the .uf2 file containing the provisioning
+bundle needs to be copied before tfm_s_ns_signed.bin.uf2. It only needs to be
+done once.
+
+-------------
+
+ *SPDX-License-Identifier: BSD-3-Clause*
+ *SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors*
diff --git a/platform/ext/target/rpi/pico_uf2.sh b/platform/ext/target/rpi/pico_uf2.sh
new file mode 100644
index 0000000..fed78a5
--- /dev/null
+++ b/platform/ext/target/rpi/pico_uf2.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+tfm_tests_dir=$1
+build_dir=$2
+spe_bin="${tfm_tests_dir}/tests_reg/spe/${build_dir}/bin"
+ns_bin="${tfm_tests_dir}/tests_reg/${build_dir}/bin"
+uf2conv.py "${spe_bin}/bl2.bin" --base 0x10000000 --convert --output "${spe_bin}/bl2.uf2" --family 0xe48bff59
+uf2conv.py "${ns_bin}/../tfm_s_ns_signed.bin" --base 0x10011000 --convert --output "${spe_bin}/tfm_s_ns_signed.uf2" --family 0xe48bff59
+uf2conv.py "${spe_bin}/provisioning_bundle.bin" --base 0x100F5000 --convert --output "${spe_bin}/provisioning_bundle.uf2" --family 0xe48bff59
\ No newline at end of file
diff --git a/platform/ext/target/rpi/rp2350/CMakeLists.txt b/platform/ext/target/rpi/rp2350/CMakeLists.txt
new file mode 100644
index 0000000..388859d
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/CMakeLists.txt
@@ -0,0 +1,324 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+
+
+# initialize pico-sdk from GIT
+set(PICO_SDK_FETCH_FROM_GIT on)
+set(PICO_PLATFORM rp2350-arm-s)
+set(SKIP_BOOT_STAGE2 1)
+
+# initialize the Raspberry Pi Pico SDK
+include(${CMAKE_CURRENT_LIST_DIR}/pico_sdk_import.cmake)
+pico_sdk_init()
+
+get_target_property(pico_link_options pico_standard_link INTERFACE_LINK_OPTIONS)
+list(FILTER pico_link_options EXCLUDE REGEX "LINKER.*--script")
+list(APPEND pico_link_options "--entry=_entry_point")
+set_target_properties(pico_standard_link PROPERTIES INTERFACE_LINK_OPTIONS "${pico_link_options}")
+set_target_properties(pico_runtime PROPERTIES INTERFACE_LINK_OPTIONS "")
+
+target_compile_options(cmsis_core
+    INTERFACE
+        ${COMPILER_CMSE_FLAG}
+)
+
+cmake_policy(SET CMP0076 NEW)
+set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+set(STATIC_ASSERT_OVERRIDE_HEADER "${CMAKE_CURRENT_LIST_DIR}/static_assert_override.h")
+add_library(static_assert_override INTERFACE)
+target_compile_options(static_assert_override
+    INTERFACE
+        "$<$<C_COMPILER_ID:Armclang>:SHELL:-include ${STATIC_ASSERT_OVERRIDE_HEADER}>"
+        "$<$<C_COMPILER_ID:GNU>:SHELL:-include ${STATIC_ASSERT_OVERRIDE_HEADER}>"
+        "$<$<C_COMPILER_ID:IAR>:SHELL:--preinclude ${STATIC_ASSERT_OVERRIDE_HEADER}>"
+)
+
+#========================= Platform region defs ===============================#
+
+add_library(platform_s_init INTERFACE)
+target_sources(platform_s_init
+    INTERFACE
+        ${CMAKE_CURRENT_LIST_DIR}/extra_init.c
+)
+
+target_link_libraries(platform_s_init
+    INTERFACE
+        pico_runtime_init
+        pico_runtime_headers
+        pico_bootrom_headers
+)
+
+target_link_options(tfm_s
+    PUBLIC
+        "--entry=_entry_point"
+)
+
+target_include_directories(platform_region_defs
+    INTERFACE
+        partition
+)
+
+target_link_libraries(platform_region_defs
+    INTERFACE
+        tfm_fih_headers
+        hardware_regs_headers
+        static_assert_override
+)
+
+target_compile_definitions(platform_region_defs
+    INTERFACE
+        PROVISIONING_CODE_PADDED_SIZE=${PROVISIONING_CODE_PADDED_SIZE}
+        PROVISIONING_VALUES_PADDED_SIZE=${PROVISIONING_VALUES_PADDED_SIZE}
+        PROVISIONING_DATA_PADDED_SIZE=${PROVISIONING_DATA_PADDED_SIZE}
+)
+
+if(NOT PLATFORM_DEFAULT_PROVISIONING)
+    add_subdirectory(${PLATFORM_DIR}/ext/common/provisioning_bundle provisioning)
+
+    if(NOT PLATFORM_DEFAULT_PROV_LINKER_SCRIPT)
+        target_add_scatter_file(provisioning_bundle
+            linker_provisioning.ld
+        )
+
+        target_compile_definitions(provisioning_bundle_scatter
+            PRIVATE
+                # u modifier in scatter file is not valid
+                NO_U_MODIFIER=1
+        )
+    endif()
+endif()
+
+if(TFM_PARTITION_CRYPTO)
+    target_include_directories(platform_crypto_keys
+        PRIVATE
+            ${CMAKE_CURRENT_LIST_DIR}
+    )
+endif()
+
+#========================= Platform common defs ===============================#
+
+# Specify the location of platform specific build dependencies.
+target_add_scatter_file(tfm_s
+    $<$<C_COMPILER_ID:ARMClang>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/armclang/tfm_common_s.sct>
+    linker_s.ld
+    $<$<C_COMPILER_ID:IAR>:${CMAKE_BINARY_DIR}/generated/platform/ext/common/iar/tfm_common_s.icf>
+)
+target_compile_definitions(tfm_s_scatter
+    PRIVATE
+        # u modifier in scatter file is not valid
+        NO_U_MODIFIER=1
+)
+target_compile_options(tfm_s_scatter
+    PUBLIC
+        ${COMPILER_CMSE_FLAG}
+)
+
+if(BL2)
+    # Pico startup and runtime init
+    target_link_libraries(bl2
+        PUBLIC
+            pico_runtime
+    )
+    target_add_scatter_file(bl2
+            $<$<C_COMPILER_ID:ARMClang>:${PLATFORM_DIR}/ext/common/armclang/tfm_common_bl2.sct>
+            linker_bl2.ld
+            $<$<C_COMPILER_ID:IAR>:${PLATFORM_DIR}/ext/common/iar/tfm_common_bl2.icf>
+    )
+    target_compile_definitions(bl2_scatter
+        PRIVATE
+            # u modifier in scatter file is not valid
+            NO_U_MODIFIER=1
+    )
+
+    target_compile_options(bl2_scatter
+        PUBLIC
+            ${COMPILER_CMSE_FLAG}
+    )
+endif()
+
+#========================= Platform Secure ====================================#
+
+target_include_directories(platform_s
+    PUBLIC
+        .
+        cmsis_drivers
+        partition
+        device/config
+        ${PLATFORM_DIR}/..
+)
+
+target_link_libraries(platform_s
+    PUBLIC
+        cmsis_core_headers
+        hardware_uart_headers
+        platform_s_init
+    PRIVATE
+        pico_crt0
+        pico_rand
+        pico_multicore
+        hardware_regs
+        hardware_flash
+        hardware_uart
+        cmsis_core
+)
+
+target_sources(platform_s
+    INTERFACE
+        $<$<STREQUAL:"${TFM_FIH_PROFILE}","HIGH">:${PLATFORM_DIR}/ext/common/template/tfm_fih_rng.c>
+    PRIVATE
+        cmsis_drivers/Driver_Flash_RPI.c
+        cmsis_drivers/Driver_USART_RPI.c
+
+        tfm_peripherals_def.c
+
+        rpi_trng.c
+
+        $<$<OR:$<BOOL:${TFM_S_REG_TEST}>,$<BOOL:${TFM_NS_REG_TEST}>>:${CMAKE_CURRENT_SOURCE_DIR}/plat_test.c>
+        $<$<BOOL:${TFM_PARTITION_PLATFORM}>:${CMAKE_CURRENT_SOURCE_DIR}/services/src/tfm_platform_system.c>
+        $<$<AND:$<BOOL:${ITS_ENCRYPTION}>,$<BOOL:${TFM_PARTITION_INTERNAL_TRUSTED_STORAGE}>>:${PLATFORM_DIR}/ext/common/template/tfm_hal_its_encryption.c>
+        $<$<NOT:$<BOOL:${PLATFORM_DEFAULT_OTP}>>:${CMAKE_CURRENT_SOURCE_DIR}/rp2350_otp.c>
+        $<$<NOT:$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>>:${CMAKE_CURRENT_SOURCE_DIR}/nv_counters.c>
+        $<$<BOOL:${TFM_MULTI_CORE_TOPOLOGY}>:${CMAKE_CURRENT_SOURCE_DIR}/tfm_hal_multi_core.c>
+        $<$<BOOL:${TFM_NS_MAILBOX_API}>:${CMAKE_CURRENT_SOURCE_DIR}/tfm_hal_mailbox.c>
+)
+
+target_compile_options(platform_s
+    PUBLIC
+        ${COMPILER_CMSE_FLAG}
+)
+
+target_compile_definitions(platform_s
+    PUBLIC
+        CMSIS_device_header=<RP2350.h>
+        PICO_UART_DEFAULT_CRLF=1
+        $<$<BOOL:${TEST_NS_FPU}>:TEST_NS_FPU>
+        $<$<BOOL:${TEST_S_FPU}>:TEST_S_FPU>
+        $<$<BOOL:${ITS_ENCRYPTION}>:ITS_ENCRYPTION>
+        $<$<BOOL:${TFM_MULTI_CORE_TOPOLOGY}>:TFM_MULTI_CORE_TOPOLOGY>
+)
+
+target_link_options(platform_s INTERFACE "LINKER:--no-warn-rwx-segments")
+
+#========================= Platform BL2 =======================================#
+
+if(BL2)
+    target_sources(platform_bl2
+        PRIVATE
+            cmsis_drivers/Driver_Flash_RPI_bl2.c
+            cmsis_drivers/Driver_USART_RPI.c
+            $<$<NOT:$<BOOL:${PLATFORM_DEFAULT_OTP}>>:${CMAKE_CURRENT_SOURCE_DIR}/rp2350_otp.c>
+            $<$<NOT:$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>>:${CMAKE_CURRENT_SOURCE_DIR}/nv_counters.c>
+    )
+
+    target_link_libraries(platform_bl2
+        PUBLIC
+            cmsis_core_headers
+            hardware_uart_headers
+        PRIVATE
+            pico_runtime_headers
+            pico_runtime_init
+            hardware_regs
+            hardware_flash
+            hardware_uart
+            cmsis_core
+    )
+
+    target_link_options(platform_bl2 INTERFACE "LINKER:--no-warn-rwx-segments")
+
+    target_include_directories(platform_bl2
+        PUBLIC
+            partition
+            retarget
+            device/config
+            device/include
+            .
+    )
+
+    target_compile_definitions(platform_bl2
+        PUBLIC
+            PICO_UART_DEFAULT_CRLF=1
+            CMSIS_device_header=<RP2350.h>
+    )
+
+    target_include_directories(bl2
+        PRIVATE
+            ${CMAKE_CURRENT_LIST_DIR}
+)
+
+endif()
+
+#========================= tfm_spm ============================================#
+
+target_sources(tfm_spm
+    PRIVATE
+        target_cfg.c
+        tfm_hal_platform.c
+        tfm_hal_isolation_rp2350.c
+        $<$<OR:$<BOOL:${CONFIG_TFM_FLIH_API}>,$<BOOL:${CONFIG_TFM_SLIH_API}>>:${PLATFORM_DIR}/ext/common/tfm_interrupts.c>
+)
+
+target_link_libraries(tfm_spm
+    PRIVATE
+        pico_bootrom_headers
+)
+
+#========================= Platform Crypto Keys ===============================#
+
+if (TFM_PARTITION_CRYPTO)
+    target_sources(platform_crypto_keys
+        PRIVATE
+            crypto_keys.c
+    )
+    target_link_libraries(platform_crypto_keys
+        PRIVATE
+            platform_s
+    )
+endif()
+
+#========================= Files for building NS platform =====================#
+
+install(FILES       ${PLATFORM_DIR}/ext/common/test_interrupt.c
+                    ${TARGET_PLATFORM_PATH}/cmsis_drivers/Driver_USART_RPI.c
+                    ${TARGET_PLATFORM_PATH}/pico-sdk.patch
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR})
+
+install(DIRECTORY   ${TARGET_PLATFORM_PATH}/device
+                    ${TARGET_PLATFORM_PATH}/cmsis_drivers
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR})
+
+install(DIRECTORY   ${PLATFORM_DIR}/ext/target/arm/drivers
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR}/ext/target/arm)
+
+install(FILES       ${TARGET_PLATFORM_PATH}/partition/region_defs.h
+                    ${TARGET_PLATFORM_PATH}/partition/flash_layout.h
+                    ${TARGET_PLATFORM_PATH}/target_cfg.h
+                    ${TARGET_PLATFORM_PATH}/tfm_peripherals_def.h
+                    ${TARGET_PLATFORM_PATH}/platform_multicore.h
+                    ${TARGET_PLATFORM_PATH}/tfm_builtin_key_ids.h
+                    ${PLATFORM_DIR}/include/tfm_plat_defs.h
+                    ${CMAKE_SOURCE_DIR}/lib/fih/inc/fih.h
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR}/include)
+
+install(FILES       ${TARGET_PLATFORM_PATH}/linker_ns.ld
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR}/linker_scripts)
+
+# copy all files from active platform directory
+install(DIRECTORY   ${TARGET_PLATFORM_PATH}/ns/
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR})
+
+install(FILES       ${TARGET_PLATFORM_PATH}/cpuarch.cmake
+                    ${TARGET_PLATFORM_PATH}/pico_sdk_import.cmake
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR})
+
+# Copy the platform specific config
+install(FILES       ${TARGET_PLATFORM_PATH}/config.cmake
+                    ${STATIC_ASSERT_OVERRIDE_HEADER}
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR})
+
+# Install test configs
+install(DIRECTORY   ${TARGET_PLATFORM_PATH}/tests
+        DESTINATION ${INSTALL_PLATFORM_NS_DIR})
diff --git a/platform/ext/target/rpi/rp2350/check_config.cmake b/platform/ext/target/rpi/rp2350/check_config.cmake
new file mode 100644
index 0000000..6a7fc73
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/check_config.cmake
@@ -0,0 +1,8 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+
+## The platform specific NV counters require OTP usage
+tfm_invalid_config((NOT PLATFORM_DEFAULT_OTP) EQUAL PLATFORM_DEFAULT_NV_COUNTERS)
diff --git a/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI.c b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI.c
new file mode 100644
index 0000000..3bf56cc
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI.c
@@ -0,0 +1,190 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_hal_device_header.h"
+#include "Driver_Flash_RPI.h"
+#include "RTE_Device.h"
+
+#include "armv8m_mpu.h"
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+#include "platform_multicore.h"
+#include "hardware/structs/sio.h"
+#endif
+
+#if (RTE_FLASH0)
+
+#define RP2350_FLASH_PAGE_SIZE        0x100        /* 256B */
+#define RP2350_FLASH_SECTOR_SIZE      0x1000       /* 4KB */
+#define RP2350_FLASH_SIZE             PICO_FLASH_SIZE_BYTES
+#define RP2350_FLASH_ERASE_VALUE      0xFF
+
+static ARM_FLASH_INFO RP2350_FLASH_DEV_DATA = {
+    .sector_info    = NULL,     /* Uniform sector layout */
+    .sector_count   = RP2350_FLASH_SIZE/ RP2350_FLASH_SECTOR_SIZE,
+    .sector_size    = RP2350_FLASH_SECTOR_SIZE,
+    .page_size      = RP2350_FLASH_PAGE_SIZE,
+    .program_unit   = RP2350_FLASH_PAGE_SIZE, /* page aligned, page multipled */
+    .erased_value   = RP2350_FLASH_ERASE_VALUE
+};
+
+#define MPU_REGION_NUMBER   8
+#define SEC_STATE_NUM 2
+
+struct mpu_state_save {
+    uint32_t mpu;
+    uint32_t shcsr;
+    uint32_t mair[2];
+    ARM_MPU_Region_t mpu_table[MPU_REGION_NUMBER];
+};
+
+static struct mpu_state_save mpu_state[SEC_STATE_NUM];
+static uint32_t irq_state = 0;
+MPU_Type* mpu_p[SEC_STATE_NUM] = {MPU, MPU_NS};
+SCB_Type* scb_p[SEC_STATE_NUM] = {SCB, SCB_NS};
+
+static inline uint32_t __save_disable_irq(void)
+{
+    uint32_t result = 0;
+
+    /* Claim lock of Flash */
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    while(!*FLASH_SPINLOCK);
+#endif
+    __ASM volatile ("mrs %0, primask \n cpsid i" : "=r" (result) :: "memory");
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    /* Signal Core1 to wait for flash */
+    sio_hw->doorbell_out_set = FLASH_DOORBELL_MASK;
+    if (CORE1_RUNNING)
+    {
+        /* Wait for Core1 to clear doorbell */
+        while(sio_hw->doorbell_out_set & FLASH_DOORBELL_MASK);
+    }
+#endif
+    return result;
+}
+
+static inline void __restore_irq(uint32_t status)
+{
+    __ASM volatile ("msr primask, %0" :: "r" (status) : "memory");
+    /* Release lock of Flash */
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    *FLASH_SPINLOCK = 0x1;
+#endif
+}
+
+/* This function must be placed in RAM, so when MPU configuration is saved and
+   flash is protected by a non-executable region MemManageFault is avoided.
+   Since PRIVDEFENA is set the system memory map is enabled for privileged code
+   and execution from RAM is available */
+static void __not_in_flash_func(mpu_state_save)
+                                            (struct rp2350_flash_dev_t* flash_dev)
+{
+    static const uint8_t mpu_attr_num = 0;
+    uint32_t memory_base = flash_dev->base;
+    uint32_t memory_limit = flash_dev->base + flash_dev->size -1;
+
+    irq_state = __save_disable_irq();
+
+    for(int i=0; i<SEC_STATE_NUM; i++) {
+
+    mpu_state[i].shcsr = scb_p[i]->SHCSR;
+    mpu_state[i].mpu = mpu_p[i]->CTRL;
+
+        if(mpu_p[i] == MPU) {
+            ARM_MPU_Disable();
+        } else {
+            ARM_MPU_Disable_NS();
+        }
+
+        for(uint8_t j = 0; j < MPU_REGION_NUMBER; j++) {
+            mpu_p[i]->RNR = j;
+            mpu_state[i].mpu_table[j].RBAR = mpu_p[i]->RBAR;
+            mpu_state[i].mpu_table[j].RLAR = mpu_p[i]->RLAR;
+            mpu_p[i]->RBAR = 0;
+            mpu_p[i]->RLAR = 0;
+        }
+
+        mpu_state[i].mair[0] = mpu_p[i]->MAIR[0];
+        mpu_state[i].mair[1] = mpu_p[i]->MAIR[1];
+
+        mpu_p[i]->MAIR[0] = 0;
+        mpu_p[i]->MAIR[1] = 0;
+
+        /* Attr0 : Device memory, nGnRE */
+        if(mpu_p[i] == MPU) {
+            ARM_MPU_SetMemAttr(mpu_attr_num,
+                               ARM_MPU_ATTR(ARM_MPU_ATTR_DEVICE,
+                                            ARM_MPU_ATTR_DEVICE_nGnRE));
+        } else {
+            ARM_MPU_SetMemAttr_NS(mpu_attr_num,
+                                  ARM_MPU_ATTR(ARM_MPU_ATTR_DEVICE,
+                                               ARM_MPU_ATTR_DEVICE_nGnRE));
+        }
+
+        mpu_p[i]->RNR = 0;
+        mpu_p[i]->RBAR = ARM_MPU_RBAR(memory_base,
+                                 ARM_MPU_SH_NON,
+                                 1,
+                                 0,
+                                 1);
+        #ifdef TFM_PXN_ENABLE
+        mpu_p[i]->RLAR = ARM_MPU_RLAR_PXN(memory_limit, 1, mpu_attr_num);
+        #else
+        mpu_p[i]->RLAR = ARM_MPU_RLAR(memory_limit, mpu_attr_num);
+        #endif
+
+        if(mpu_p[i] == MPU) {
+            ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
+        } else {
+            ARM_MPU_Enable_NS(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
+        }
+    }
+}
+
+static void __not_in_flash_func(mpu_state_restore)(void)
+{
+    for(int i=0; i<SEC_STATE_NUM; i++) {
+
+        if(mpu_p[i] == MPU) {
+            ARM_MPU_Disable();
+        } else {
+            ARM_MPU_Disable_NS();
+        }
+
+        for(uint8_t j = 0; j < MPU_REGION_NUMBER; j++) {
+            mpu_p[i]->RNR = j;
+            mpu_p[i]->RBAR = mpu_state[i].mpu_table[j].RBAR;
+            mpu_p[i]->RLAR = mpu_state[i].mpu_table[j].RLAR;
+        }
+
+        mpu_p[i]->MAIR[0] = mpu_state[i].mair[0];
+        mpu_p[i]->MAIR[1] = mpu_state[i].mair[1];
+
+        __DMB();
+        mpu_p[i]->CTRL = mpu_state[i].mpu;
+#ifdef SCB_SHCSR_MEMFAULTENA_Msk
+        scb_p[i]->SHCSR = mpu_state[i].shcsr;
+#endif
+        __DSB();
+        __ISB();
+
+    }
+
+    __restore_irq(irq_state);
+}
+
+static rp2350_flash_dev_t RP2350_FLASH_DEV = {
+    .data = &RP2350_FLASH_DEV_DATA,
+    .base = XIP_BASE,
+    .size = RP2350_FLASH_SIZE,
+    .save_mpu_state = mpu_state_save,
+    .restore_mpu_state = mpu_state_restore
+};
+
+
+RPI_RP2350_FLASH(RP2350_FLASH_DEV, RP2350_FLASH);
+#endif /* RTE_FLASH0 */
diff --git a/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI.h b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI.h
new file mode 100644
index 0000000..3664758
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI.h
@@ -0,0 +1,209 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __DRIVER_FLASH_RPI_H__
+#define __DRIVER_FLASH_RPI_H__
+
+#include "Driver_Flash.h"
+#include "hardware/flash.h"
+#include <string.h>
+
+#ifndef ARG_UNUSED
+#define ARG_UNUSED(arg)  ((void)arg)
+#endif
+
+/* Driver version */
+#define ARM_FLASH_DRV_VERSION   ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0)
+
+static const ARM_DRIVER_VERSION DriverVersion = {
+    ARM_FLASH_API_VERSION,  /* Defined in the CMSIS Flash Driver header file */
+    ARM_FLASH_DRV_VERSION
+};
+
+/**
+ * Data width values for ARM_FLASH_CAPABILITIES::data_width
+ * \ref ARM_FLASH_CAPABILITIES
+ */
+ enum {
+    DATA_WIDTH_8BIT   = 0u,
+    DATA_WIDTH_16BIT,
+    DATA_WIDTH_32BIT,
+    DATA_WIDTH_ENUM_SIZE
+};
+
+/* Flash Status */
+static ARM_FLASH_STATUS FlashStatus = {0, 0, 0};
+
+/**
+ * \brief Flash driver capability macro definitions \ref ARM_FLASH_CAPABILITIES
+ */
+/* Flash Ready event generation capability values */
+#define EVENT_READY_NOT_AVAILABLE   (0u)
+#define EVENT_READY_AVAILABLE       (1u)
+
+/* Chip erase capability values */
+#define CHIP_ERASE_NOT_SUPPORTED    (0u)
+#define CHIP_ERASE_SUPPORTED        (1u)
+
+static inline ARM_DRIVER_VERSION ARM_Flash_GetVersion(void)
+{
+    return DriverVersion;
+}
+
+/* Driver Capabilities */
+static const ARM_FLASH_CAPABILITIES DriverCapabilities = {
+    EVENT_READY_NOT_AVAILABLE,
+    DATA_WIDTH_8BIT,
+    CHIP_ERASE_NOT_SUPPORTED
+};
+
+/*
+ * ARM FLASH device structure
+ */
+typedef struct rp2350_flash_dev_t{
+    ARM_FLASH_INFO* data;               /* FLASH data */
+    uint32_t base;                      /* Flash base address, used for flash
+                                           reads */
+    uint32_t size;                      /* Flash size */
+    void (*save_mpu_state)(struct rp2350_flash_dev_t* dev);
+                                        /*!< Function to save MPU settings */
+    void (*restore_mpu_state)(void);
+                                        /*!< Function to restore MPU settings */
+} rp2350_flash_dev_t;
+
+/* Driver Capabilities */
+static const ARM_FLASH_CAPABILITIES PicoDriverCapabilities = {
+    0, /* event_ready */
+    0, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */
+    0, /* erase_chip */
+    0, /* reserved */
+};
+
+static inline ARM_FLASH_CAPABILITIES Pico_Driver_GetCapabilities(void)
+{
+    return PicoDriverCapabilities;
+}
+
+static inline int32_t ARM_Flash_Uninitialize(void)
+{
+    /* Nothing to be done */
+    return ARM_DRIVER_OK;
+}
+
+static inline int32_t ARM_Flash_PowerControl(ARM_POWER_STATE state)
+{
+    switch (state) {
+    case ARM_POWER_FULL:
+        /* Nothing to be done */
+        return ARM_DRIVER_OK;
+        break;
+
+    case ARM_POWER_OFF:
+    case ARM_POWER_LOW:
+    default:
+        return ARM_DRIVER_ERROR_UNSUPPORTED;
+    }
+}
+
+static inline ARM_FLASH_STATUS ARM_Flash_GetStatus(void)
+{
+    return FlashStatus;
+}
+
+/*
+ * \brief Macro for Pico Flash Driver
+ *
+ * \param[out] FLASH_DRIVER_NAME  Resulting Driver name
+ */
+#define RPI_RP2350_FLASH(FLASH_DEV, FLASH_DRIVER_NAME)                          \
+                                                                              \
+static int32_t FLASH_DRIVER_NAME##_Initialize(                                \
+                                            ARM_Flash_SignalEvent_t cb_event) \
+{                                                                             \
+    ARG_UNUSED(cb_event);                                                     \
+    return ARM_DRIVER_OK;                                                     \
+}                                                                             \
+                                                                              \
+static int32_t FLASH_DRIVER_NAME##_ReadData(uint32_t addr,                    \
+                                            void *data,                       \
+                                            uint32_t cnt)                     \
+{                                                                             \
+    if ((addr+cnt) >= FLASH_DEV.size) {                                       \
+        return ARM_DRIVER_ERROR_PARAMETER;                                    \
+    }                                                                         \
+                                                                              \
+    memcpy(data, (void *)(addr + FLASH_DEV.base), cnt);                       \
+                                                                              \
+    return ARM_DRIVER_OK;                                                     \
+}                                                                             \
+                                                                              \
+static int32_t FLASH_DRIVER_NAME##_ProgramData(uint32_t addr,                 \
+                                               const void *data,              \
+                                               uint32_t cnt)                  \
+{                                                                             \
+    if ((addr+cnt) >= FLASH_DEV.size) {                                       \
+        return ARM_DRIVER_ERROR_PARAMETER;                                    \
+    }                                                                         \
+                                                                              \
+    if ((cnt < FLASH_DEV.data->program_unit) ||                               \
+        (cnt % FLASH_DEV.data->program_unit) ||                               \
+        (addr % FLASH_DEV.data->page_size)) {                                 \
+        return ARM_DRIVER_ERROR_PARAMETER;                                    \
+    }                                                                         \
+                                                                              \
+    FLASH_DEV.save_mpu_state(&FLASH_DEV);                                     \
+                                                                              \
+    flash_range_program(addr, data, cnt);                                     \
+                                                                              \
+    FLASH_DEV.restore_mpu_state();                                            \
+                                                                              \
+    return ARM_DRIVER_OK;                                                     \
+}                                                                             \
+                                                                              \
+static int32_t FLASH_DRIVER_NAME##_EraseSector(uint32_t addr)                 \
+{                                                                             \
+    if (addr >= FLASH_DEV.size) {                                             \
+        return ARM_DRIVER_ERROR_PARAMETER;                                    \
+    }                                                                         \
+                                                                              \
+    if (addr % FLASH_DEV.data->sector_size) {                                 \
+        return ARM_DRIVER_ERROR_PARAMETER;                                    \
+    }                                                                         \
+                                                                              \
+    FLASH_DEV.save_mpu_state(&FLASH_DEV);                                     \
+                                                                              \
+    flash_range_erase(addr, FLASH_DEV.data->sector_size);                     \
+                                                                              \
+    FLASH_DEV.restore_mpu_state();                                            \
+                                                                              \
+    return ARM_DRIVER_OK;                                                     \
+}                                                                             \
+                                                                              \
+static int32_t FLASH_DRIVER_NAME##_EraseChip(void)                            \
+{                                                                             \
+    return ARM_DRIVER_ERROR_UNSUPPORTED;                                      \
+}                                                                             \
+                                                                              \
+static ARM_FLASH_INFO * FLASH_DRIVER_NAME##_GetInfo(void)                     \
+{                                                                             \
+    return FLASH_DEV.data;                                                    \
+}                                                                             \
+                                                                              \
+ARM_DRIVER_FLASH FLASH_DRIVER_NAME = {                                        \
+    ARM_Flash_GetVersion,                                                     \
+    Pico_Driver_GetCapabilities,                                              \
+    FLASH_DRIVER_NAME##_Initialize,                                           \
+    ARM_Flash_Uninitialize,                                                   \
+    ARM_Flash_PowerControl,                                                   \
+    FLASH_DRIVER_NAME##_ReadData,                                             \
+    FLASH_DRIVER_NAME##_ProgramData,                                          \
+    FLASH_DRIVER_NAME##_EraseSector,                                          \
+    FLASH_DRIVER_NAME##_EraseChip,                                            \
+    ARM_Flash_GetStatus,                                                      \
+    FLASH_DRIVER_NAME##_GetInfo                                               \
+};
+
+#endif /* __DRIVER_FLASH_RPI_H__ */
diff --git a/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI_bl2.c b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI_bl2.c
new file mode 100644
index 0000000..5878a48
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_Flash_RPI_bl2.c
@@ -0,0 +1,61 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_hal_device_header.h"
+#include "Driver_Flash_RPI.h"
+#include "RTE_Device.h"
+
+#if (RTE_FLASH0)
+
+#define RP2350_FLASH_PAGE_SIZE        0x100        /* 256B */
+#define RP2350_FLASH_SECTOR_SIZE      0x1000       /* 4KB */
+#define RP2350_FLASH_SIZE             PICO_FLASH_SIZE_BYTES
+#define RP2350_FLASH_ERASE_VALUE      0xFF
+
+static ARM_FLASH_INFO RP2350_FLASH_DEV_DATA = {
+    .sector_info    = NULL,     /* Uniform sector layout */
+    .sector_count   = RP2350_FLASH_SIZE/ RP2350_FLASH_SECTOR_SIZE,
+    .sector_size    = RP2350_FLASH_SECTOR_SIZE,
+    .page_size      = RP2350_FLASH_PAGE_SIZE,
+    .program_unit   = RP2350_FLASH_PAGE_SIZE, /* page aligned, page multipled */
+    .erased_value   = RP2350_FLASH_ERASE_VALUE
+};
+
+static uint32_t irq_state = 0;
+
+static inline uint32_t __save_disable_irq(void)
+{
+    uint32_t result = 0;
+
+    __ASM volatile ("mrs %0, primask \n cpsid i" : "=r" (result) :: "memory");
+    return result;
+}
+
+static inline void __restore_irq(uint32_t status)
+{
+    __ASM volatile ("msr primask, %0" :: "r" (status) : "memory");
+}
+
+/* No need to save and restore MPU configuration for bl2 */
+static void dummy_save(struct rp2350_flash_dev_t* flash_dev){
+    ARG_UNUSED(flash_dev);
+    irq_state = __save_disable_irq();
+}
+static void dummy_restore(void){
+    __restore_irq(irq_state);
+}
+
+static rp2350_flash_dev_t RP2350_FLASH_DEV = {
+    .data = &RP2350_FLASH_DEV_DATA,
+    .base = XIP_BASE,
+    .size = RP2350_FLASH_SIZE,
+    .save_mpu_state = dummy_save,
+    .restore_mpu_state = dummy_restore
+};
+
+
+RPI_RP2350_FLASH(RP2350_FLASH_DEV, RP2350_FLASH);
+#endif /* RTE_FLASH0 */
diff --git a/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_USART_RPI.c b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_USART_RPI.c
new file mode 100644
index 0000000..46360d4
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_USART_RPI.c
@@ -0,0 +1,16 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "Driver_USART_RPI.h"
+#include "RTE_Device.h"
+
+
+#if (defined (RTE_USART0) && (RTE_USART0 == 1))
+#define UART_TX_PIN 0
+#define UART_RX_PIN 1
+
+ARM_DRIVER_USART_RP2350((uart_inst_t *)UART0_BASE, driver_usart0, UART_RX_PIN, UART_TX_PIN);
+#endif /* RTE_USART0 */
diff --git a/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_USART_RPI.h b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_USART_RPI.h
new file mode 100644
index 0000000..09a591a
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cmsis_drivers/Driver_USART_RPI.h
@@ -0,0 +1,380 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __DRIVER_USART_RPI_H__
+#define __DRIVER_USART_RPI_H__
+
+#include "Driver_USART.h"
+#include "hardware/gpio.h"
+#include "hardware/uart.h"
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+#include "platform_multicore.h"
+#include "hardware/structs/sio.h"
+#endif
+
+#ifndef ARG_UNUSED
+#define ARG_UNUSED(arg)  (void)arg
+#endif
+
+#define ARM_USART_DRV_VERSION    ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0)  /* driver version */
+
+/* Driver Version */
+static const ARM_DRIVER_VERSION DriverVersion = {
+    ARM_USART_API_VERSION,
+    ARM_USART_DRV_VERSION
+};
+
+/* Driver Capabilities */
+static const ARM_USART_CAPABILITIES DriverCapabilities = {
+    1, /* supports UART (Asynchronous) mode */
+    0, /* supports Synchronous Master mode */
+    0, /* supports Synchronous Slave mode */
+    0, /* supports UART Single-wire mode */
+    0, /* supports UART IrDA mode */
+    0, /* supports UART Smart Card mode */
+    0, /* Smart Card Clock generator available */
+    0, /* RTS Flow Control available */
+    0, /* CTS Flow Control available */
+    0, /* Transmit completed event: \ref ARM_USART_EVENT_TX_COMPLETE */
+    0, /* Signal receive character timeout event: \ref ARM_USART_EVENT_RX_TIMEOUT */
+    0, /* RTS Line: 0=not available, 1=available */
+    0, /* CTS Line: 0=not available, 1=available */
+    0, /* DTR Line: 0=not available, 1=available */
+    0, /* DSR Line: 0=not available, 1=available */
+    0, /* DCD Line: 0=not available, 1=available */
+    0, /* RI Line: 0=not available, 1=available */
+    0, /* Signal CTS change event: \ref ARM_USART_EVENT_CTS */
+    0, /* Signal DSR change event: \ref ARM_USART_EVENT_DSR */
+    0, /* Signal DCD change event: \ref ARM_USART_EVENT_DCD */
+    0, /* Signal RI change event: \ref ARM_USART_EVENT_RI */
+    0  /* Reserved (must be zero) */
+};
+
+
+typedef struct {
+    uart_inst_t *dev;                   /* UART device */
+    uint32_t tx_nbr_bytes;              /* Number of bytes transfered */
+    uint32_t rx_nbr_bytes;              /* Number of bytes recevied */
+    uint32_t default_baudrate;          /* UART default baudrate */
+    uint8_t rx_pin_num;                 /* RX pin number for GPIO config */
+    uint8_t tx_pin_num;                 /* TX pin number for GPIO config */
+    ARM_USART_SignalEvent_t cb_event;   /* Callback function for events */
+} UARTx_Resources;
+//
+//   Functions
+//
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+static inline void spinlock_claim()
+{
+    /* Reading a spinlock register attempts to claim it, returning nonzero
+        * if the claim was successful and 0 if unsuccessful */
+    while(!*UART_SPINLOCK);
+}
+
+static inline void spinlock_release()
+{
+    /* Writing to a spinlock register releases it */
+    *UART_SPINLOCK = 0x1u;
+}
+#endif
+
+static ARM_DRIVER_VERSION ARM_USART_GetVersion(void)
+{
+  return DriverVersion;
+}
+
+static ARM_USART_CAPABILITIES ARM_USART_GetCapabilities(void)
+{
+  return DriverCapabilities;
+}
+
+static inline int32_t ARM_USARTx_Initialize(UARTx_Resources *uart_dev)
+{
+    gpio_set_function(uart_dev->rx_pin_num, GPIO_FUNC_UART);
+    gpio_set_function(uart_dev->tx_pin_num, GPIO_FUNC_UART);
+    uart_init(uart_dev->dev, uart_dev->default_baudrate);
+
+    return ARM_DRIVER_OK;
+}
+
+static inline int32_t ARM_USARTx_Uninitialize(UARTx_Resources *uart_dev)
+{
+    uart_deinit(uart_dev->dev);
+
+    return ARM_DRIVER_OK;
+}
+
+static int32_t ARM_USARTx_PowerControl(UARTx_Resources *uart_dev, ARM_POWER_STATE state)
+{
+    ARG_UNUSED(uart_dev);
+
+    switch (state) {
+    case ARM_POWER_OFF:
+    case ARM_POWER_LOW:
+        return ARM_DRIVER_ERROR_UNSUPPORTED;
+    case ARM_POWER_FULL:
+        /* Nothing to be done */
+        return ARM_DRIVER_OK;
+    /* default:  The default is not defined intentionally to force the
+     *           compiler to check that all the enumeration values are
+     *           covered in the switch.*/
+    }
+}
+
+static inline int32_t ARM_USARTx_Send(UARTx_Resources *uart_dev,
+                                      const void *data,
+                                      uint32_t num)
+{
+    const uint8_t *p_data;
+
+    if ((data == NULL) || (num == 0U)) {
+        /* Invalid parameters */
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    spinlock_claim();
+#endif
+
+    p_data = (const uint8_t *)data;
+
+    /* Resets previous TX counter */
+    uart_dev->tx_nbr_bytes = 0;
+
+    while (uart_dev->tx_nbr_bytes != num) {
+        /* Waits until UART is ready to transmit */
+        while (!uart_is_writable(uart_dev->dev)) {
+        }
+        /* As UART is ready to transmit at this point, the write function can
+            * not return any transmit error */
+        uart_putc(uart_dev->dev, *p_data);
+
+        uart_dev->tx_nbr_bytes++;
+        p_data++;
+    }
+    uart_tx_wait_blocking(uart_dev->dev);
+
+    if (uart_dev->cb_event != NULL) {
+        uart_dev->cb_event(ARM_USART_EVENT_SEND_COMPLETE);
+    }
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    spinlock_release();
+#endif
+
+    return ARM_DRIVER_OK;
+}
+
+static inline int32_t ARM_USARTx_Receive(UARTx_Resources *uart_dev,
+                                         void *data, uint32_t num)
+{
+    uint8_t *p_data;
+
+    if ((data == NULL) || (num == 0U)) {
+        // Invalid parameters
+        return ARM_DRIVER_ERROR_PARAMETER;
+    }
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    spinlock_claim();
+#endif
+
+    p_data = (uint8_t *)data;
+
+    /* Resets previous RX counter */
+    uart_dev->rx_nbr_bytes = 0;
+
+    while (uart_dev->rx_nbr_bytes != num) {
+        /* Waits until one character is received */
+        while (uart_is_readable(uart_dev->dev)) {
+            *p_data = uart_getc(uart_dev->dev);
+
+            uart_dev->rx_nbr_bytes++;
+            p_data++;
+        }
+    }
+
+    if (uart_dev->cb_event != NULL) {
+        uart_dev->cb_event(ARM_USART_EVENT_RECEIVE_COMPLETE);
+    }
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    spinlock_release();
+#endif
+    return ARM_DRIVER_OK;
+}
+
+static inline uint32_t ARM_USARTx_GetTxCount(UARTx_Resources *uart_dev)
+{
+    return uart_dev->tx_nbr_bytes;
+}
+
+static inline uint32_t ARM_USARTx_GetRxCount(UARTx_Resources *uart_dev)
+{
+    return uart_dev->rx_nbr_bytes;
+}
+
+static inline int32_t ARM_USARTx_Control(UARTx_Resources *uart_dev,
+                                         uint32_t control,
+                                         uint32_t arg)
+{
+    switch (control & ARM_USART_CONTROL_Msk) {
+#ifdef UART_TX_RX_CONTROL_ENABLED
+        case ARM_USART_CONTROL_TX:
+            if (arg == 0) {
+                uart_get_hw(uart)->cr &= ~UART_UARTCR_TXE_BITS;
+            } else if (arg == 1) {
+                uart_get_hw(uart)->cr |= UART_UARTCR_TXE_BITS;
+            } else {
+                return ARM_DRIVER_ERROR_PARAMETER;
+            }
+            break;
+        case ARM_USART_CONTROL_RX:
+            if (arg == 0) {
+                uart_get_hw(uart)->cr &= ~UART_UARTCR_RXE_BITS;
+            } else if (arg == 1) {
+                uart_get_hw(uart)->cr |= UART_UARTCR_RXE_BITS;
+            } else {
+                return ARM_DRIVER_ERROR_PARAMETER;
+            }
+            break;
+#endif
+        case ARM_USART_MODE_ASYNCHRONOUS:
+            uart_set_baudrate(uart_dev->dev, arg);
+            break;
+        /* Unsupported command */
+        default:
+            return ARM_DRIVER_ERROR_UNSUPPORTED;
+    }
+
+    /* UART Data bits */
+    if (control & ARM_USART_DATA_BITS_Msk) {
+        /* Data bit is not configurable */
+        return ARM_DRIVER_ERROR_UNSUPPORTED;
+    }
+
+    /* UART Parity */
+    if (control & ARM_USART_PARITY_Msk) {
+        /* Parity is not configurable */
+        return ARM_USART_ERROR_PARITY;
+    }
+
+    /* USART Stop bits */
+    if (control & ARM_USART_STOP_BITS_Msk) {
+        /* Stop bit is not configurable */
+        return ARM_USART_ERROR_STOP_BITS;
+    }
+
+    return ARM_DRIVER_OK;
+}
+
+/*
+ * \brief Macro for USART Driver
+ *
+ * \param[in]  USART_DEV          uart_inst_t pointer
+ * \param[out] USART_DRIVER_NAME  Resulting Driver name
+ */
+#define ARM_DRIVER_USART_RP2350(USART_DEV, USART_DRIVER_NAME, RX_PIN, TX_PIN)   \
+static UARTx_Resources USART_DRIVER_NAME##_DEV = {                            \
+    .dev = USART_DEV,                                                         \
+    .default_baudrate = 115200,                                               \
+    .tx_nbr_bytes = 0,                                                        \
+    .rx_nbr_bytes = 0,                                                        \
+    .rx_pin_num = RX_PIN,                                                     \
+    .tx_pin_num = TX_PIN,                                                     \
+    .cb_event = NULL,                                                         \
+};                                                                            \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_Initialize(                                \
+                                        ARM_USART_SignalEvent_t cb_event)     \
+{                                                                             \
+    USART_DRIVER_NAME##_DEV.cb_event = cb_event;                              \
+                                                                              \
+    return ARM_USARTx_Initialize(&USART_DRIVER_NAME##_DEV);                   \
+}                                                                             \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_Uninitialize(void)                         \
+{                                                                             \
+    return ARM_USARTx_Uninitialize(&USART_DRIVER_NAME##_DEV);                 \
+}                                                                             \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_PowerControl(ARM_POWER_STATE state)        \
+{                                                                             \
+    return ARM_USARTx_PowerControl(&USART_DRIVER_NAME##_DEV, state);          \
+}                                                                             \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_Send(const void *data, uint32_t num)       \
+{                                                                             \
+    return ARM_USARTx_Send(&USART_DRIVER_NAME##_DEV, data, num);              \
+}                                                                             \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_Receive(void *data, uint32_t num)          \
+{                                                                             \
+    return ARM_USARTx_Receive(&USART_DRIVER_NAME##_DEV, data, num);           \
+}                                                                             \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_Transfer(const void *data_out,             \
+                                            void *data_in,                    \
+                                            uint32_t num)                     \
+{                                                                             \
+    ARG_UNUSED(data_out);                                                     \
+    ARG_UNUSED(data_in);                                                      \
+    ARG_UNUSED(num);                                                          \
+                                                                              \
+    return ARM_DRIVER_ERROR_UNSUPPORTED;                                      \
+}                                                                             \
+                                                                              \
+static uint32_t USART_DRIVER_NAME##_GetTxCount(void)                          \
+{                                                                             \
+    return ARM_USARTx_GetTxCount(&USART_DRIVER_NAME##_DEV);                   \
+}                                                                             \
+                                                                              \
+static uint32_t USART_DRIVER_NAME##_GetRxCount(void)                          \
+{                                                                             \
+    return ARM_USARTx_GetRxCount(&USART_DRIVER_NAME##_DEV);                   \
+}                                                                             \
+static int32_t USART_DRIVER_NAME##_Control(uint32_t control, uint32_t arg)    \
+{                                                                             \
+    return ARM_USARTx_Control(&USART_DRIVER_NAME##_DEV, control, arg);        \
+}                                                                             \
+                                                                              \
+static ARM_USART_STATUS USART_DRIVER_NAME##_GetStatus(void)                   \
+{                                                                             \
+    ARM_USART_STATUS status = {0, 0, 0, 0, 0, 0, 0, 0};                       \
+    return status;                                                            \
+}                                                                             \
+                                                                              \
+static int32_t USART_DRIVER_NAME##_SetModemControl(                           \
+                                             ARM_USART_MODEM_CONTROL control) \
+{                                                                             \
+    ARG_UNUSED(control);                                                      \
+    return ARM_DRIVER_ERROR_UNSUPPORTED;                                      \
+}                                                                             \
+                                                                              \
+static ARM_USART_MODEM_STATUS USART_DRIVER_NAME##_GetModemStatus(void)        \
+{                                                                             \
+    ARM_USART_MODEM_STATUS modem_status = {0, 0, 0, 0, 0};                    \
+    return modem_status;                                                      \
+}                                                                             \
+                                                                              \
+extern ARM_DRIVER_USART USART_DRIVER_NAME;                                    \
+ARM_DRIVER_USART USART_DRIVER_NAME   = {                                      \
+    ARM_USART_GetVersion,                                                     \
+    ARM_USART_GetCapabilities,                                                \
+    USART_DRIVER_NAME##_Initialize,                                           \
+    USART_DRIVER_NAME##_Uninitialize,                                         \
+    USART_DRIVER_NAME##_PowerControl,                                         \
+    USART_DRIVER_NAME##_Send,                                                 \
+    USART_DRIVER_NAME##_Receive,                                              \
+    USART_DRIVER_NAME##_Transfer,                                             \
+    USART_DRIVER_NAME##_GetTxCount,                                           \
+    USART_DRIVER_NAME##_GetRxCount,                                           \
+    USART_DRIVER_NAME##_Control,                                              \
+    USART_DRIVER_NAME##_GetStatus,                                            \
+    USART_DRIVER_NAME##_SetModemControl,                                      \
+    USART_DRIVER_NAME##_GetModemStatus                                        \
+}
+
+#endif  /* __DRIVER_USART_RPI_H__ */
diff --git a/platform/ext/target/rpi/rp2350/cmsis_drivers/RTE_Device.h b/platform/ext/target/rpi/rp2350/cmsis_drivers/RTE_Device.h
new file mode 100644
index 0000000..5624bbd
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cmsis_drivers/RTE_Device.h
@@ -0,0 +1,24 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
+
+#ifndef __RTE_DEVICE_H
+#define __RTE_DEVICE_H
+
+// <q> USART (Universal synchronous - asynchronous receiver transmitter) [Driver_USART0]
+// <i> Configuration settings for Driver_USART0 in component ::Drivers:USART
+#define   RTE_USART0                                1
+
+// <q> USART (Universal synchronous - asynchronous receiver transmitter) [Driver_USART1]
+// <i> Configuration settings for Driver_USART1 in component ::Drivers:USART
+#define   RTE_USART1                                0
+
+// <q> Flash device emulated in SRAM [Driver_Flash0]
+// <i> Configuration settings for Driver_Flash0 in component ::Drivers:Flash
+#define   RTE_FLASH0                                1
+
+#endif  /* __RTE_DEVICE_H */
\ No newline at end of file
diff --git a/platform/ext/target/rpi/rp2350/config.cmake b/platform/ext/target/rpi/rp2350/config.cmake
new file mode 100644
index 0000000..342f996
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/config.cmake
@@ -0,0 +1,48 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+
+set(PROVISIONING_KEYS_CONFIG      ""        CACHE FILEPATH  "The config file which has the keys and seeds for provisioning")
+
+if(BL2)
+    set(BL2_TRAILER_SIZE 0x800 CACHE STRING "Trailer size")
+else()
+    #No header if no bootloader, but keep IMAGE_CODE_SIZE the same
+    set(BL2_TRAILER_SIZE 0xC00 CACHE STRING "Trailer size")
+endif()
+
+# Platform-specific configurations
+set(TFM_MULTI_CORE_TOPOLOGY           OFF  CACHE BOOL "Enable Multicore topology")
+if (TFM_MULTI_CORE_TOPOLOGY)
+    set(TFM_NS_MAILBOX_API                ON)
+    set(TFM_PARTITION_NS_AGENT_MAILBOX    ON)
+    set(TFM_NS_CUSTOM_API                 ON)
+else()
+    set(TFM_NS_MAILBOX_API                OFF)
+    set(TFM_PARTITION_NS_AGENT_MAILBOX    OFF)
+    set(TFM_NS_CUSTOM_API                 OFF)
+endif()
+
+set(CONFIG_TFM_USE_TRUSTZONE          ON)
+set(MCUBOOT_USE_PSA_CRYPTO            ON               CACHE BOOL      "Enable the cryptographic abstraction layer to use PSA Crypto APIs")
+set(MCUBOOT_SIGNATURE_TYPE            "EC-P256"        CACHE STRING    "Algorithm to use for signature validation [RSA-2048, RSA-3072, EC-P256, EC-P384]")
+set(MCUBOOT_HW_KEY                    OFF              CACHE BOOL      "Whether to embed the entire public key in the image metadata instead of the hash only")
+set(MCUBOOT_BUILTIN_KEY               ON               CACHE BOOL      "Use builtin key(s) for validation, no public key data is embedded into the image metadata")
+
+set(PROVISIONING_CODE_PADDED_SIZE       "0x2000"  CACHE STRING    "")
+set(PROVISIONING_VALUES_PADDED_SIZE     "0x400"   CACHE STRING    "")
+set(PROVISIONING_DATA_PADDED_SIZE       "0x400"   CACHE STRING    "")
+
+set(PICO_SDK_FETCH_FROM_GIT_TAG         "2.0.0"   CACHE STRING       "Use the define Pico SDK tag for the build")
+
+set(TFM_MBEDCRYPTO_PLATFORM_EXTRA_CONFIG_PATH ${CMAKE_CURRENT_LIST_DIR}/mbedtls_extra_config.h CACHE PATH "Config to append to standard Mbed Crypto config, used by platforms to cnfigure feature support")
+
+set(PLATFORM_DEFAULT_PROV_LINKER_SCRIPT OFF          CACHE BOOL      "Use default provisioning linker script")
+set(ITS_ENCRYPTION                      ON           CACHE BOOL      "Enable authenticated encryption of ITS files using platform specific APIs")
+set(PLATFORM_DEFAULT_NV_SEED            OFF          CACHE BOOL      "Use default NV seed implementation.")
+set(PLATFORM_DEFAULT_OTP                OFF          CACHE BOOL      "Use trusted on-chip flash to implement OTP memory")
+set(PLATFORM_DEFAULT_NV_COUNTERS        OFF          CACHE BOOL      "Use default nv counter implementation.")
+
+set(PLATFORM_DEFAULT_CRYPTO_KEYS        OFF          CACHE BOOL      "Use default crypto keys implementation.")
diff --git a/platform/ext/target/rpi/rp2350/config_tfm_target.h b/platform/ext/target/rpi/rp2350/config_tfm_target.h
new file mode 100644
index 0000000..dc90516
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/config_tfm_target.h
@@ -0,0 +1,19 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __CONFIG_TFM_TARGET_H__
+#define __CONFIG_TFM_TARGET_H__
+
+/* Use stored NV seed to provide entropy */
+#define CRYPTO_NV_SEED                         0
+
+/* Use external RNG to provide entropy */
+#define CRYPTO_EXT_RNG                         1
+
+/* Run the scheduler after handling a secure interrupt if the NSPE was pre-empted */
+#define CONFIG_TFM_SCHEDULE_WHEN_NS_INTERRUPTED 1
+
+#endif /* __CONFIG_TFM_TARGET_H__ */
diff --git a/platform/ext/target/rpi/rp2350/cpuarch.cmake b/platform/ext/target/rpi/rp2350/cpuarch.cmake
new file mode 100644
index 0000000..d049ea2
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/cpuarch.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+
+# Set architecture and CPU
+set(TFM_SYSTEM_PROCESSOR cortex-m33)
+set(TFM_SYSTEM_ARCHITECTURE armv8-m.main)
+
+set(TFM_SYSTEM_DSP OFF)
+set(CONFIG_TFM_FP_ARCH "fpv5-d16")
+set(CONFIG_TFM_FP_ARCH_ASM "FPv5_D16")
diff --git a/platform/ext/target/rpi/rp2350/crypto_keys.c b/platform/ext/target/rpi/rp2350/crypto_keys.c
new file mode 100644
index 0000000..4ea25be
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/crypto_keys.c
@@ -0,0 +1,155 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include <string.h>
+#include "tfm_plat_crypto_keys.h"
+#include "tfm_builtin_key_ids.h"
+#include "tfm_plat_otp.h"
+#include "psa_manifest/pid.h"
+#include "tfm_builtin_key_loader.h"
+
+#define NUMBER_OF_ELEMENTS_OF(x) sizeof(x)/sizeof(*x)
+#define MAPPED_TZ_NS_AGENT_DEFAULT_CLIENT_ID -0x3c000000
+#define TFM_NS_PARTITION_ID                  MAPPED_TZ_NS_AGENT_DEFAULT_CLIENT_ID
+#define MAPPED_RSE_MBOX_NS_AGENT_DEFAULT_CLIENT_ID -0x04000000
+#define TFM_NS_MAILBOX_PARTITION_ID          MAPPED_RSE_MBOX_NS_AGENT_DEFAULT_CLIENT_ID
+
+static enum tfm_plat_err_t tfm_plat_get_huk(uint8_t *buf, size_t buf_len,
+                                            size_t *key_len,
+                                            psa_key_bits_t *key_bits,
+                                            psa_algorithm_t *algorithm,
+                                            psa_key_type_t *type)
+{
+    enum tfm_plat_err_t err;
+
+    err = tfm_plat_otp_read(PLAT_OTP_ID_HUK, buf_len, buf);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    err = tfm_plat_otp_get_size(PLAT_OTP_ID_HUK, key_len);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    *key_bits = *key_len * 8;
+    *algorithm = PSA_ALG_HKDF(PSA_ALG_SHA_256);
+    *type = PSA_KEY_TYPE_DERIVE;
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+#ifdef TFM_PARTITION_INITIAL_ATTESTATION
+static enum tfm_plat_err_t tfm_plat_get_iak(uint8_t *buf, size_t buf_len,
+                                            size_t *key_len,
+                                            psa_key_bits_t *key_bits,
+                                            psa_algorithm_t *algorithm,
+                                            psa_key_type_t *type)
+{
+    enum tfm_plat_err_t err;
+#ifndef SYMMETRIC_INITIAL_ATTESTATION
+    psa_ecc_family_t curve_type;
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
+
+    err = tfm_plat_otp_read(PLAT_OTP_ID_IAK_LEN,
+                            sizeof(size_t), (uint8_t*)key_len);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+    *key_bits = *key_len * 8;
+
+    if (buf_len < *key_len) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+    err = tfm_plat_otp_read(PLAT_OTP_ID_IAK_TYPE,
+                            sizeof(psa_algorithm_t), (uint8_t*)algorithm);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    *type = PSA_KEY_TYPE_HMAC;
+#else /* SYMMETRIC_INITIAL_ATTESTATION */
+    err = tfm_plat_otp_read(PLAT_OTP_ID_IAK_TYPE, sizeof(psa_ecc_family_t),
+                            &curve_type);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    *algorithm = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
+    *type = PSA_KEY_TYPE_ECC_KEY_PAIR(curve_type);
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
+
+    return tfm_plat_otp_read(PLAT_OTP_ID_IAK, *key_len, buf);
+}
+#endif /* TFM_PARTITION_INITIAL_ATTESTATION */
+
+#ifdef TFM_PARTITION_INITIAL_ATTESTATION
+/**
+ * @brief Table describing per-user key policy for the IAK
+ *
+ */
+static const tfm_plat_builtin_key_per_user_policy_t g_iak_per_user_policy[] = {
+    {.user = TFM_SP_INITIAL_ATTESTATION,
+#ifdef SYMMETRIC_INITIAL_ATTESTATION
+        .usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT,
+#else
+        .usage = PSA_KEY_USAGE_SIGN_HASH,
+#endif /* SYMMETRIC_INITIAL_ATTESTATION */
+    },
+#ifdef TEST_S_ATTESTATION
+    {.user = TFM_SP_SECURE_TEST_PARTITION, .usage = PSA_KEY_USAGE_VERIFY_HASH},
+#endif /* TEST_S_ATTESTATION */
+#ifdef TEST_NS_ATTESTATION
+    {.user = TFM_NS_PARTITION_ID, .usage = PSA_KEY_USAGE_VERIFY_HASH},
+    {.user = TFM_NS_MAILBOX_PARTITION_ID, .usage = PSA_KEY_USAGE_VERIFY_HASH},
+#endif /* TEST_NS_ATTESTATION */
+};
+#endif /* TFM_PARTITION_INITIAL_ATTESTATION */
+
+/**
+ * @brief Table describing per-key user policies
+ *
+ */
+static const tfm_plat_builtin_key_policy_t g_builtin_keys_policy[] = {
+    {.key_id = TFM_BUILTIN_KEY_ID_HUK, .per_user_policy = 0, .usage = PSA_KEY_USAGE_DERIVE},
+#ifdef TFM_PARTITION_INITIAL_ATTESTATION
+    {.key_id = TFM_BUILTIN_KEY_ID_IAK,
+     .per_user_policy = NUMBER_OF_ELEMENTS_OF(g_iak_per_user_policy),
+     .policy_ptr = g_iak_per_user_policy},
+#endif /* TFM_PARTITION_INITIAL_ATTESTATION */
+};
+
+/**
+ * @brief Table describing the builtin-in keys (plaform keys) available in the platform. Note
+ *        that to bind the keys to the tfm_builtin_key_loader driver, the lifetime must be
+ *        explicitly set to the one associated to the driver, i.e. TFM_BUILTIN_KEY_LOADER_LIFETIME
+ */
+static const tfm_plat_builtin_key_descriptor_t g_builtin_keys_desc[] = {
+    {.key_id = TFM_BUILTIN_KEY_ID_HUK,
+     .slot_number = TFM_BUILTIN_KEY_SLOT_HUK,
+     .lifetime = TFM_BUILTIN_KEY_LOADER_LIFETIME,
+     .loader_key_func = tfm_plat_get_huk},
+#ifdef TFM_PARTITION_INITIAL_ATTESTATION
+    {.key_id = TFM_BUILTIN_KEY_ID_IAK,
+     .slot_number = TFM_BUILTIN_KEY_SLOT_IAK,
+     .lifetime = TFM_BUILTIN_KEY_LOADER_LIFETIME,
+     .loader_key_func = tfm_plat_get_iak},
+#endif /* TFM_PARTITION_INITIAL_ATTESTATION */
+};
+
+size_t tfm_plat_builtin_key_get_policy_table_ptr(const tfm_plat_builtin_key_policy_t *desc_ptr[])
+{
+    *desc_ptr = &g_builtin_keys_policy[0];
+    return NUMBER_OF_ELEMENTS_OF(g_builtin_keys_policy);
+}
+
+size_t tfm_plat_builtin_key_get_desc_table_ptr(const tfm_plat_builtin_key_descriptor_t *desc_ptr[])
+{
+    *desc_ptr = &g_builtin_keys_desc[0];
+    return NUMBER_OF_ELEMENTS_OF(g_builtin_keys_desc);
+}
diff --git a/platform/ext/target/rpi/rp2350/device/config/device_cfg.h b/platform/ext/target/rpi/rp2350/device/config/device_cfg.h
new file mode 100644
index 0000000..f83e8d5
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/device/config/device_cfg.h
@@ -0,0 +1,19 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __DEVICE_CFG_H__
+#define __DEVICE_CFG_H__
+
+/**
+ * \file device_cfg.h
+ * \brief Configurations for peripherals defined in
+ * platform's device definition
+ */
+
+#define DEFAULT_UART_CONTROL 0
+#define DEFAULT_UART_BAUDRATE  115200
+
+#endif  /* __DEVICE_CFG_H__ */
diff --git a/platform/ext/target/rpi/rp2350/extra_init.c b/platform/ext/target/rpi/rp2350/extra_init.c
new file mode 100644
index 0000000..bda0fbc
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/extra_init.c
@@ -0,0 +1,117 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "pico/runtime.h"
+#include "pico/runtime_init.h"
+#include "hardware/structs/scb.h"
+#ifdef PSA_API_TEST_CRYPTO
+#include "hardware/ticks.h"
+#include "hardware/clocks.h"
+#endif
+
+#include "stdint.h"
+
+/* Do not use __cmsis_start */
+#define __PROGRAM_START
+#include "tfm_hal_device_header.h"
+
+void copy_zero_tables(void) {
+    typedef struct {
+        uint32_t const* src;
+        uint32_t* dest;
+        uint32_t  wlen;
+    } __copy_table_t;
+
+    typedef struct {
+        uint32_t* dest;
+        uint32_t  wlen;
+    } __zero_table_t;
+
+    extern const __copy_table_t __copy_table_start__;
+    extern const __copy_table_t __copy_table_end__;
+    extern const __zero_table_t __zero_table_start__;
+    extern const __zero_table_t __zero_table_end__;
+
+    for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {
+        for(uint32_t i=0u; i<pTable->wlen; ++i) {
+            pTable->dest[i] = pTable->src[i];
+        }
+    }
+
+    for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {
+        for(uint32_t i=0u; i<pTable->wlen; ++i) {
+            pTable->dest[i] = 0u;
+        }
+    }
+}
+
+void hard_assertion_failure(void) {
+    SPM_ASSERT(0);
+}
+
+static void runtime_run_initializers_from(uintptr_t *from) {
+
+    /* Start and end points of the constructor list, defined by the linker script. */
+    extern uintptr_t __preinit_array_end;
+
+    /* Call each function in the list, based on the mask
+       We have to take the address of the symbols, as __preinit_array_start *is*
+       the first function value, not the address of it. */
+    for (uintptr_t *p = from; p < &__preinit_array_end; p++) {
+        uintptr_t val = *p;
+        ((void (*)(void))val)();
+    }
+}
+
+void runtime_run_initializers(void) {
+    extern uintptr_t __preinit_array_start;
+    runtime_run_initializers_from(&__preinit_array_start);
+}
+
+/* We keep the per-core initializers in the standard __preinit_array so a standard C library
+   initialization will fo the core 0 initialization, however we also want to be able to find
+   them after the fact so that we can run them on core 1. Per core initializers have sections
+   __preinit_array.ZZZZZ.nnnnn i.e. the ZZZZZ sorts below all the standard __preinit_array.nnnnn
+   values, and then we sort within the ZZZZZ.
+
+   We create a dummy initializer in __preinit_array.YYYYY (between the standard initializers
+   and the per core initializers), so we find the first per core initializer. Whilst we could
+   have done this via an entry in the linker script, we want to preserve backwards compatibility
+   with RP2040 custom linker scripts. */
+static void first_per_core_initializer(void) {}
+PICO_RUNTIME_INIT_FUNC(first_per_core_initializer, "YYYYY");
+
+void runtime_run_per_core_initializers(void) {
+    runtime_run_initializers_from(&__pre_init_first_per_core_initializer);
+}
+
+extern uint32_t __vectors_start__;
+extern uint32_t __INITIAL_SP;
+extern uint32_t __STACK_LIMIT;
+extern uint64_t __STACK_SEAL;
+
+void runtime_init(void) {
+    scb_hw->vtor = (uintptr_t) &__vectors_start__;
+    copy_zero_tables();
+
+    __disable_irq();
+    __set_PSP((uint32_t)(&__INITIAL_SP));
+
+    __set_MSPLIM((uint32_t)(&__STACK_LIMIT));
+    __set_PSPLIM((uint32_t)(&__STACK_LIMIT));
+
+    __TZ_set_STACKSEAL_S((uint32_t *)(&__STACK_SEAL));
+
+    runtime_run_initializers();
+
+#ifdef PSA_API_TEST_CRYPTO
+    /* RSA Key generation test takes very long. Use 4 times slower WD
+       reference tick when it is enabled. */
+    tick_start(TICK_WATCHDOG, 4 * clock_get_hz(clk_ref) / MHZ);
+#endif
+
+    SystemInit();
+}
diff --git a/platform/ext/target/rpi/rp2350/linker_bl2.ld b/platform/ext/target/rpi/rp2350/linker_bl2.ld
new file mode 100644
index 0000000..5dfd04c
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/linker_bl2.ld
@@ -0,0 +1,284 @@
+;/*
+; *  SPDX-License-Identifier: BSD-3-Clause
+; *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+; *
+; */
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+#include "region_defs.h"
+MEMORY
+{
+    FLASH (rx)  : ORIGIN = BL2_CODE_START, LENGTH = BL2_CODE_SIZE
+    RAM   (rwx) : ORIGIN = BL2_DATA_START, LENGTH = BL2_DATA_SIZE
+#ifdef __ENABLE_SCRATCH__
+    SCRATCH_X(rwx) : ORIGIN = SCRATCH_X_START, LENGTH = SCRATCH_X_SIZE
+    SCRATCH_Y(rwx) : ORIGIN = SCRATCH_Y_START, LENGTH = SCRATCH_Y_SIZE
+#endif
+}
+__heap_size__  = BL2_HEAP_SIZE;
+__msp_stack_size__ = BL2_MSP_STACK_SIZE;
+ENTRY(Reset_Handler)
+SECTIONS
+{
+    .flash_begin : {
+        __flash_binary_start = .;
+    } > FLASH
+    .text (READONLY) :
+    {
+        __logical_binary_start = .;
+        __Vectors_Start = .;
+        KEEP(*(.vectors))
+        __Vectors_End = .;
+        __Vectors_Size = __Vectors_End - __Vectors_Start;
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.embedded_block))
+        __embedded_block_end = .;
+        KEEP (*(.reset))
+        __end__ = .;
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+        /* .copy.table */
+        . = ALIGN(4);
+        __copy_table_start__ = .;
+#ifdef CODE_SHARING
+        LONG (LOADADDR(.tfm_shared_symbols))
+        LONG (ADDR(.tfm_shared_symbols))
+        LONG (SIZEOF(.tfm_shared_symbols) / 4)
+#endif
+        LONG (LOADADDR(.data))
+        LONG (ADDR(.data))
+        LONG (SIZEOF(.data) / 4)
+        __copy_table_end__ = .;
+        /* .zero.table */
+        . = ALIGN(4);
+        __zero_table_start__ = .;
+        LONG (ADDR(.bss))
+        LONG (SIZEOF(.bss) / 4)
+        __zero_table_end__ = .;
+        KEEP(*(.init))
+        *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+        KEEP(*(.fini))
+        /* .ctors */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        /* .dtors */
+         *crtbegin.o(.dtors)
+         *crtbegin?.o(.dtors)
+         *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+         *(SORT(.dtors.*))
+         *(.dtors)
+        *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+        *(.srodata*)
+        . = ALIGN(4);
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+        . = ALIGN(4);
+        KEEP(*(.eh_frame*))
+        . = ALIGN(4);
+    } > FLASH
+    /* Note the boot2 section is optional, and should be discarded if there is
+       no reference to it *inside* the binary, as it is not called by the
+       bootrom. (The bootrom performs a simple best-effort XIP setup and
+       leaves it to the binary to do anything more sophisticated.) However
+       there is still a size limit of 256 bytes, to ensure the boot2 can be
+       stored in boot RAM.
+       Really this is a "XIP setup function" -- the name boot2 is historic and
+       refers to its dual-purpose on RP2040, where it also handled vectoring
+       from the bootrom into the user image.
+    */
+    .boot2 : {
+        __boot2_start__ = .;
+        *(.boot2)
+        __boot2_end__ = .;
+    } > FLASH
+    ASSERT(__boot2_end__ - __boot2_start__ <= 256,
+        "ERROR: Pico second stage bootloader must be no more than 256 bytes in size")
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > FLASH
+    __binary_info_end = .;
+#ifdef CODE_SHARING
+    /* The code sharing between bootloader and runtime firmware requires to
+     * share the global variables. Section size must be equal with
+     * SHARED_SYMBOL_AREA_SIZE defined in region_defs.h
+     */
+    .tfm_shared_symbols : ALIGN(4)
+    {
+        *(.data.mbedtls_calloc_func)
+        *(.data.mbedtls_free_func)
+        *(.data.mbedtls_exit)
+        *(.data.memset_func)
+        . = ALIGN(SHARED_SYMBOL_AREA_SIZE);
+    } > RAM AT > FLASH
+    ASSERT(SHARED_SYMBOL_AREA_SIZE % 4 == 0, "SHARED_SYMBOL_AREA_SIZE must be divisible by 4")
+#endif
+    .tfm_bl2_shared_data : ALIGN(32)
+    {
+        . += BOOT_TFM_SHARED_DATA_SIZE;
+    } > RAM
+    Image$$SHARED_DATA$$RW$$Base = ADDR(.tfm_bl2_shared_data);
+    Image$$SHARED_DATA$$RW$$Limit = ADDR(.tfm_bl2_shared_data) + SIZEOF(.tfm_bl2_shared_data);
+    . = ALIGN(4);
+   .ram_vector_table (NOLOAD): {
+        *(.ram_vector_table)
+    } > RAM
+    .data : ALIGN(4)
+    {
+        __data_start__ = .;
+        *(vtable)
+        *(.time_critical*)
+        /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+        *(.text*)
+        . = ALIGN(4);
+        *(.rodata*)
+        . = ALIGN(4);
+        *(.data*)
+        *(.sdata*)
+        . = ALIGN(4);
+        *(.after_data.*)
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+        KEEP(*(.jcr*))
+        . = ALIGN(4);
+        /* All data end */
+        __data_end__ = .;
+    } > RAM AT > FLASH
+    __etext = LOADADDR(.data);
+    Image$$ER_DATA$$Base = ADDR(.data);
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM
+    .bss : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __bss_start__ = .;
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+        *(COMMON)
+        PROVIDE(__global_pointer$ = . + 2K);
+        *(.sbss*)
+        . = ALIGN(4);
+        __bss_end__ = .;
+    } > RAM
+#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
+    .msp_stack ALIGN(32) :
+    {
+        . += __msp_stack_size__ - 0x8;
+    } > RAM
+    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
+    .msp_stack_seal_res :
+    {
+        . += 0x8;
+    } > RAM
+    __StackSeal = ADDR(.msp_stack_seal_res);
+#else
+    .msp_stack ALIGN(32) :
+    {
+        . += __msp_stack_size__;
+    } > RAM
+    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
+#endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
+#ifdef __ENABLE_SCRATCH__
+    /* Start and end symbols must be word-aligned */
+    .scratch_x : {
+        __scratch_x_start__ = .;
+        *(.scratch_x.*)
+        . = ALIGN(4);
+        __scratch_x_end__ = .;
+    } > SCRATCH_X AT > FLASH
+    __scratch_x_source__ = LOADADDR(.scratch_x);
+    .scratch_y : {
+        __scratch_y_start__ = .;
+        *(.scratch_y.*)
+        . = ALIGN(4);
+        __scratch_y_end__ = .;
+    } > SCRATCH_Y AT > FLASH
+    __scratch_y_source__ = LOADADDR(.scratch_y);
+#endif
+    .heap (NOLOAD): ALIGN(8)
+    {
+        . = ALIGN(8);
+        __end__ = .;
+        PROVIDE(end = .);
+        __HeapBase = .;
+        KEEP(*(.heap*))
+        . += __heap_size__;
+        __HeapLimit = .;
+        __heap_limit = .; /* Add for _sbrk */
+    } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
+    /* .stack*_dummy section doesn't contains any symbols. It is only
+     * used for linker to calculate size of stack sections, and assign
+     * values to stack symbols later
+     *
+     * stack1 section may be empty/missing if platform_launch_core1 is not used */
+    /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+     * stack is not used then all of SCRATCH_X is free.
+     */
+#ifdef __ENABLE_SCRATCH__
+    .stack1_dummy (NOLOAD):
+    {
+        *(.stack1*)
+    } > SCRATCH_X
+    .stack_dummy (NOLOAD):
+    {
+        KEEP(*(.stack*))
+    } > SCRATCH_Y
+#endif
+    .flash_end : {
+        PROVIDE(__flash_binary_end = .);
+    } > FLASH =0xaa
+    PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
+#ifdef __ENABLE_SCRATCH__
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+    __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+    __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+    __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+#endif
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary")
+    /* todo assert on extra code */
+}
diff --git a/platform/ext/target/rpi/rp2350/linker_ns.ld b/platform/ext/target/rpi/rp2350/linker_ns.ld
new file mode 100644
index 0000000..3e27443
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/linker_ns.ld
@@ -0,0 +1,242 @@
+;/*
+; *  SPDX-License-Identifier: BSD-3-Clause
+; *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+; *
+; */
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+#include "region_defs.h"
+/* Include file with definitions for section alignments.
+ * Note: it should be included after region_defs.h to let platform define
+ * default values if needed. */
+MEMORY
+{
+    FLASH (rx)  : ORIGIN = NS_CODE_START, LENGTH = NS_CODE_SIZE
+    RAM   (rwx) : ORIGIN = NS_DATA_START, LENGTH = NS_DATA_SIZE
+#ifdef __ENABLE_SCRATCH__
+    SCRATCH_X(rwx) : ORIGIN = SRAM_SCRATCH_X_BASE, LENGTH = SCRATCH_X_SIZE
+    SCRATCH_Y(rwx) : ORIGIN = SRAM_SCRATCH_Y_BASE, LENGTH = SCRATCH_Y_SIZE
+#endif
+}
+
+__heap_size__  = NS_HEAP_SIZE;
+__stack_size__ = NS_STACK_SIZE;
+ENTRY(_entry_point)
+SECTIONS
+{
+    .vectors :
+    {
+        __logical_binary_start = .;
+        __Vectors_Start__ = .;
+        KEEP(*(.vectors))
+        __Vectors_End = .;
+        __Vectors_Size = __Vectors_End - __Vectors_Start__;
+        __end__ = .;
+    } > FLASH
+
+#if defined(NS_VECTOR_ALLOCATED_SIZE)
+    ASSERT(. <= ADDR(.vectors) + NS_VECTOR_ALLOCATED_SIZE, ".vectors section size overflow.")
+    . = ADDR(.vectors) + NS_VECTOR_ALLOCATED_SIZE;
+#endif
+
+    .CORE1_ENTRY : ALIGN(4)
+    {
+        KEEP (*(.core1_ns_entry*))
+    }
+
+    .PICO_RESET : ALIGN(4)
+    {
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.embedded_block))
+        __embedded_block_end = .;
+        KEEP (*(.reset))
+    } > FLASH
+
+    .text (READONLY) :
+    {
+        *(.text*)
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        /* .copy.table */
+        . = ALIGN(4);
+        __copy_table_start__ = .;
+        LONG (__etext)
+        LONG (__data_start__)
+        LONG ((__data_end__ - __data_start__) / 4)
+        LONG (__etext2)
+        LONG (__data2_start__)
+        LONG ((__data2_end__ - __data2_start__) / 4)
+        __copy_table_end__ = .;
+
+        /* .zero.table */
+        . = ALIGN(4);
+        __zero_table_start__ = .;
+        LONG (__bss_start__)
+        LONG ((__bss_end__ - __bss_start__) / 4)
+        LONG (__bss2_start__)
+        LONG ((__bss2_end__ - __bss2_start__) / 4)
+        __zero_table_end__ = .;
+
+        KEEP(*(.init))
+        KEEP(*(.fini))
+
+        /* .ctors */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+
+        /* .dtors */
+         *crtbegin.o(.dtors)
+         *crtbegin?.o(.dtors)
+         *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+         *(SORT(.dtors.*))
+         *(.dtors)
+
+        *(.rodata*)
+
+        KEEP(*(.eh_frame*))
+    } > FLASH
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > FLASH
+    __binary_info_end = .;
+
+    __etext2 = ALIGN(4);
+
+    .data : AT (__etext2)
+    {
+        __data2_start__ = .;
+        *(vtable)
+        *(.data*)
+
+        KEEP(*(.jcr*))
+        . = ALIGN(4);
+        /* All data end */
+        __data2_end__ = .;
+    } > RAM
+
+    /* Pico crt0.S copies the __data_start__-__data_end__ region, but we handle
+     * that in our runtime_init */
+     __etext = 0;
+     __data_start__ = 0;
+     __data_end__ = 0;
+
+    .ram_vector_table (NOLOAD): ALIGN(256)  {
+        *(.ram_vector_table)
+    } > RAM
+
+    .bss :
+    {
+        . = ALIGN(4);
+        __bss2_start__ = .;
+        *(.bss*)
+        *(COMMON)
+        . = ALIGN(4);
+        __bss2_end__ = .;
+    } > RAM
+
+    /* Pico crt0.S zeros the __bss_start__-__bss_end__ region, but we handle
+     * that in our runtime_init */
+     __bss_start__ = 0;
+     __bss_end__ = 0;
+
+    bss_size = __bss2_end__ - __bss2_start__;
+
+    .heap : ALIGN(8)
+    {
+        . = ALIGN(8);
+        __end__ = .;
+        PROVIDE(end = .);
+        __HeapBase = .;
+        . += __heap_size__;
+        __HeapLimit = .;
+        __heap_limit = .; /* Add for _sbrk */
+    } > RAM
+
+    #ifdef __ENABLE_SCRATCH__
+    /* Start and end symbols must be word-aligned */
+    .scratch_x : {
+        __scratch_x_start__ = .;
+        *(.scratch_x.*)
+        . = ALIGN(4);
+        __scratch_x_end__ = .;
+    } > SCRATCH_X AT > FLASH
+    __scratch_x_source__ = LOADADDR(.scratch_x);
+    .scratch_y : {
+        __scratch_y_start__ = .;
+        *(.scratch_y.*)
+        . = ALIGN(4);
+        __scratch_y_end__ = .;
+    } > SCRATCH_Y AT > FLASH
+    __scratch_y_source__ = LOADADDR(.scratch_y);
+
+    .stack1_dummy (NOLOAD):
+    {
+        *(.stack1*)
+    } > SCRATCH_X
+    .stack_dummy (NOLOAD):
+    {
+        KEEP(*(.stack*))
+    } > SCRATCH_Y
+
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+    __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+    __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+    __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+    PROVIDE(__stack = __StackTop);
+#endif
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary")
+}
diff --git a/platform/ext/target/rpi/rp2350/linker_provisioning.ld b/platform/ext/target/rpi/rp2350/linker_provisioning.ld
new file mode 100644
index 0000000..a613940
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/linker_provisioning.ld
@@ -0,0 +1,50 @@
+;/*
+; *  SPDX-License-Identifier: BSD-3-Clause
+; *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+; *
+; */
+
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+
+#include "region_defs.h"
+
+MEMORY
+{
+    CODE (rx) : ORIGIN = PROVISIONING_BUNDLE_CODE_START, LENGTH = PROVISIONING_BUNDLE_CODE_SIZE
+    DATA (rw) : ORIGIN = PROVISIONING_BUNDLE_DATA_START, LENGTH = PROVISIONING_BUNDLE_DATA_SIZE
+    VALUES (r) : ORIGIN = PROVISIONING_BUNDLE_VALUES_START, LENGTH = PROVISIONING_BUNDLE_VALUES_SIZE
+}
+
+ENTRY(do_provisioning)
+
+SECTIONS
+{
+    CODE :
+    {
+        *provisioning_code.o(DO_PROVISION)
+        *(.text*)
+        *(.time_critical*)
+    } > CODE
+
+    RW_DATA :
+    {
+        *(COMMON .data*)
+    } > DATA
+
+    RO_DATA :
+    {
+        *(EXCLUDE_FILE (*provisioning_data.o) .rodata*)
+    } > DATA
+
+    BSS_DATA :
+    {
+        *(.bss*)
+    } > DATA
+
+    VALUES :
+    {
+        *provisioning_data.o(.rodata.data)
+    } > VALUES
+
+}
diff --git a/platform/ext/target/rpi/rp2350/linker_s.ld b/platform/ext/target/rpi/rp2350/linker_s.ld
new file mode 100644
index 0000000..084b1fc
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/linker_s.ld
@@ -0,0 +1,576 @@
+;/*
+; *  SPDX-License-Identifier: BSD-3-Clause
+; *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+; *
+; */
+/* Linker script to configure memory regions. */
+/* This file will be run trough the pre-processor. */
+#include "region_defs.h"
+/* Include file with definitions for section alignments.
+ * Note: it should be included after region_defs.h to let platform define
+ * default values if needed. */
+#include "tfm_s_linker_alignments.h"
+MEMORY
+{
+  FLASH    (rx)  : ORIGIN = S_CODE_START, LENGTH = S_CODE_SIZE
+  RAM      (rw)  : ORIGIN = S_DATA_START, LENGTH = S_DATA_SIZE
+#if defined(S_RAM_CODE_START)
+  CODE_RAM (rwx) : ORIGIN = S_RAM_CODE_START, LENGTH = S_RAM_CODE_SIZE
+#endif
+#ifdef __ENABLE_SCRATCH__
+  SCRATCH_X(rwx) : ORIGIN = SCRATCH_X_START, LENGTH = SCRATCH_X_SIZE
+  SCRATCH_Y(rwx) : ORIGIN = SCRATCH_Y_START, LENGTH = SCRATCH_Y_SIZE
+#endif
+}
+
+#ifndef TFM_LINKER_VENEERS_START
+#define TFM_LINKER_VENEERS_START ALIGN(TFM_LINKER_VENEERS_ALIGNMENT)
+#endif
+
+#ifndef TFM_LINKER_VENEERS_END
+#define TFM_LINKER_VENEERS_END ALIGN(TFM_LINKER_VENEERS_ALIGNMENT)
+#endif
+
+#define VENEERS() \
+/* \
+ * Place the CMSE Veneers (containing the SG instruction) after the code, in \
+ * a separate at least 32 bytes aligned region so that the SAU can \
+ * programmed to just set this region as Non-Secure Callable. \
+ */ \
+.gnu.sgstubs TFM_LINKER_VENEERS_START : \
+{ \
+    *(.gnu.sgstubs*) \
+} > FLASH \
+/* GCC always places veneers at the end of .gnu.sgstubs section, so the only \
+ * way to align the end of .gnu.sgstubs section is to align start of the \
+ * next section */ \
+.sgstubs_end : TFM_LINKER_VENEERS_END \
+{ \
+} > FLASH
+
+__msp_stack_size__ = S_MSP_STACK_SIZE;
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+    /* Start address of the code. */
+    Image$$PT_RO_START$$Base = ADDR(.TFM_VECTORS);
+
+    .TFM_VECTORS : ALIGN(4)
+    {
+        __logical_binary_start = .;
+        __vectors_start__ = .;
+        KEEP(*(.vectors))
+        . = ALIGN(4);
+        __vectors_end__ = .;
+    } > FLASH
+
+    ASSERT(__vectors_start__ != __vectors_end__, ".vectors should not be empty")
+
+#if defined(S_CODE_VECTOR_TABLE_SIZE)
+    ASSERT(. <= ADDR(.TFM_VECTORS) + S_CODE_VECTOR_TABLE_SIZE, ".TFM_VECTORS section size overflow.")
+    . = ADDR(.TFM_VECTORS) + S_CODE_VECTOR_TABLE_SIZE;
+#endif
+
+    .PICO_RESET : ALIGN(4)
+    {
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.embedded_block))
+        __embedded_block_end = .;
+        KEEP (*(.reset))
+    } > FLASH
+
+#if defined(CONFIG_TFM_USE_TRUSTZONE) && !defined(TFM_LINKER_VENEERS_LOCATION_END)
+    VENEERS()
+#endif
+
+    /**** Section for holding partition RO load data */
+    /*
+     * Sort the partition info by priority to guarantee the initing order.
+     * The first loaded partition will be inited at last in SFN model.
+     */
+    .TFM_SP_LOAD_LIST ALIGN(4) :
+    {
+       KEEP(*(.part_load_priority_00))
+       KEEP(*(.part_load_priority_01))
+       KEEP(*(.part_load_priority_02))
+       KEEP(*(.part_load_priority_03))
+    } > FLASH
+    Image$$TFM_SP_LOAD_LIST$$RO$$Base = ADDR(.TFM_SP_LOAD_LIST);
+    Image$$TFM_SP_LOAD_LIST$$RO$$Limit = ADDR(.TFM_SP_LOAD_LIST) + SIZEOF(.TFM_SP_LOAD_LIST);
+
+    /**** PSA RoT RO part (CODE + RODATA) start here */
+    . = ALIGN(TFM_LINKER_PSA_ROT_LINKER_CODE_ALIGNMENT);
+    Image$$TFM_PSA_CODE_START$$Base = .;
+
+    .TFM_PSA_ROT_LINKER ALIGN(TFM_LINKER_PSA_ROT_LINKER_CODE_ALIGNMENT) :
+    {
+        *tfm_psa_rot_partition*:(SORT_BY_ALIGNMENT(.text*))
+        *tfm_psa_rot_partition*:(SORT_BY_ALIGNMENT(.rodata*))
+        *(TFM_*_PSA-ROT_ATTR_FN)
+        . = ALIGN(TFM_LINKER_PSA_ROT_LINKER_CODE_ALIGNMENT);
+    } > FLASH
+
+    Image$$TFM_PSA_ROT_LINKER$$RO$$Base = ADDR(.TFM_PSA_ROT_LINKER);
+    Image$$TFM_PSA_ROT_LINKER$$RO$$Limit = ADDR(.TFM_PSA_ROT_LINKER) + SIZEOF(.TFM_PSA_ROT_LINKER);
+    Image$$TFM_PSA_ROT_LINKER$$Base = ADDR(.TFM_PSA_ROT_LINKER);
+    Image$$TFM_PSA_ROT_LINKER$$Limit = ADDR(.TFM_PSA_ROT_LINKER) + SIZEOF(.TFM_PSA_ROT_LINKER);
+
+    /**** PSA RoT RO part (CODE + RODATA) end here */
+    Image$$TFM_PSA_CODE_END$$Base = .;
+
+    /**** APPLICATION RoT RO part (CODE + RODATA) start here */
+    Image$$TFM_APP_CODE_START$$Base = .;
+
+    .TFM_APP_ROT_LINKER ALIGN(TFM_LINKER_APP_ROT_LINKER_CODE_ALIGNMENT) :
+    {
+        *tfm_app_rot_partition*:(SORT_BY_ALIGNMENT(.text*))
+        *tfm_app_rot_partition*:(SORT_BY_ALIGNMENT(.rodata*))
+        *(TFM_*_APP-ROT_ATTR_FN)
+        . = ALIGN(TFM_LINKER_APP_ROT_LINKER_CODE_ALIGNMENT);
+    } > FLASH
+
+    Image$$TFM_APP_ROT_LINKER$$RO$$Base = ADDR(.TFM_APP_ROT_LINKER);
+    Image$$TFM_APP_ROT_LINKER$$RO$$Limit = ADDR(.TFM_APP_ROT_LINKER) + SIZEOF(.TFM_APP_ROT_LINKER);
+    Image$$TFM_APP_ROT_LINKER$$Base = ADDR(.TFM_APP_ROT_LINKER);
+    Image$$TFM_APP_ROT_LINKER$$Limit = ADDR(.TFM_APP_ROT_LINKER) + SIZEOF(.TFM_APP_ROT_LINKER);
+
+    /**** APPLICATION RoT RO part (CODE + RODATA) end here */
+    Image$$TFM_APP_CODE_END$$Base = .;
+
+#if defined(S_RAM_CODE_START)
+    /* Flash drivers code that gets copied from Flash */
+    .ER_CODE_SRAM ALIGN(S_RAM_CODE_START, 4) :
+    {
+        *libflash_drivers*:(SORT_BY_ALIGNMENT(.text*))
+        *libflash_drivers*:(SORT_BY_ALIGNMENT(.rodata*))
+        KEEP(*(.ramfunc))
+        . = ALIGN(4); /* This alignment is needed to make the section size 4 bytes aligned */
+    } > CODE_RAM AT > FLASH
+
+    ASSERT(S_RAM_CODE_START % 4 == 0, "S_RAM_CODE_START must be divisible by 4")
+
+    Image$$ER_CODE_SRAM$$RO$$Base = ADDR(.ER_CODE_SRAM);
+    Image$$ER_CODE_SRAM$$RO$$Limit = ADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
+    Image$$ER_CODE_SRAM$$Base = ADDR(.ER_CODE_SRAM);
+    Image$$ER_CODE_SRAM$$Limit = ADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
+#endif
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > FLASH
+    __binary_info_end = .;
+
+    /* Data copy is done by extra_init */
+    __etext = 0;
+    __data_start__ = 0;
+    __data_end__ = 0;
+
+    .ER_TFM_CODE ALIGN(4) (READONLY) :
+    {
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        /* .copy.table */
+        . = ALIGN(4);
+        __copy_table_start__ = .;
+#ifdef RAM_VECTORS_SUPPORT
+        /* Copy interrupt vectors from flash to RAM */
+        LONG (__vectors_start__)                            /* From */
+        LONG (__ram_vectors_start__)                        /* To   */
+        LONG ((__vectors_end__ - __vectors_start__) / 4)    /* Size */
+#endif
+        LONG (LOADADDR(.TFM_DATA))
+        LONG (ADDR(.TFM_DATA))
+        LONG (SIZEOF(.TFM_DATA) / 4)
+
+        LONG (LOADADDR(.TFM_PSA_ROT_LINKER_DATA))
+        LONG (ADDR(.TFM_PSA_ROT_LINKER_DATA))
+        LONG (SIZEOF(.TFM_PSA_ROT_LINKER_DATA) / 4)
+
+        LONG (LOADADDR(.TFM_APP_ROT_LINKER_DATA))
+        LONG (ADDR(.TFM_APP_ROT_LINKER_DATA))
+        LONG (SIZEOF(.TFM_APP_ROT_LINKER_DATA) / 4)
+
+#if defined (S_RAM_CODE_START)
+        LONG (LOADADDR(.ER_CODE_SRAM))
+        LONG (ADDR(.ER_CODE_SRAM))
+        LONG (SIZEOF(.ER_CODE_SRAM) / 4)
+#endif
+        __copy_table_end__ = .;
+
+        /* .zero.table */
+        . = ALIGN(4);
+        __zero_table_start__ = .;
+        LONG (ADDR(.TFM_BSS))
+        LONG (SIZEOF(.TFM_BSS) / 4)
+        LONG (ADDR(.TFM_PSA_ROT_LINKER_BSS))
+        LONG (SIZEOF(.TFM_PSA_ROT_LINKER_BSS) / 4)
+
+        LONG (ADDR(.TFM_APP_ROT_LINKER_BSS))
+        LONG (SIZEOF(.TFM_APP_ROT_LINKER_BSS) / 4)
+#if defined(CONFIG_TFM_PARTITION_META)
+        LONG (ADDR(.TFM_SP_META_PTR))
+        LONG (SIZEOF(.TFM_SP_META_PTR) / 4)
+#endif
+        __zero_table_end__ = .;
+
+        *startup*(.text*)
+        /* Remove flash driver related files */
+        EXCLUDE_FILE (*libplatform_s*:*Flash_RPI*) *libplatform_s*:(SORT_BY_ALIGNMENT(.text*))
+        *libtfm_spm*:(SORT_BY_ALIGNMENT(.text*))
+
+        EXCLUDE_FILE (*libplatform_s*:*Flash_RPI*) *libplatform_s*:*(.rodata*)
+        *libtfm_spm*:*(.rodata*)
+    } > FLASH
+
+    .TFM_UNPRIV_CODE ALIGN(TFM_LINKER_UNPRIV_CODE_ALIGNMENT) :
+    {
+        /* Remove flash driver related files */
+        EXCLUDE_FILE (*libplatform_s*:*Flash_RPI*) *(SORT_BY_ALIGNMENT(.text*))
+
+        KEEP(*(.init))
+        KEEP(*(.fini))
+
+        /* .ctors */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+
+        /* .dtors */
+         *crtbegin.o(.dtors)
+         *crtbegin?.o(.dtors)
+         *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+         *(SORT(.dtors.*))
+         *(.dtors)
+
+        *(SORT_BY_ALIGNMENT(.rodata*))
+        . = ALIGN(4);
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+
+        KEEP(*(.eh_frame*))
+        . = ALIGN(TFM_LINKER_UNPRIV_CODE_ALIGNMENT);
+    } > FLASH
+    Image$$TFM_UNPRIV_CODE_START$$RO$$Base = ADDR(.TFM_UNPRIV_CODE);
+    Image$$TFM_UNPRIV_CODE_END$$RO$$Limit = ADDR(.TFM_UNPRIV_CODE) + SIZEOF(.TFM_UNPRIV_CODE);
+
+#if defined(CONFIG_TFM_USE_TRUSTZONE) && defined(TFM_LINKER_VENEERS_LOCATION_END)
+    VENEERS()
+#endif
+
+    /* Position tag */
+    . = ALIGN(TFM_LINKER_PT_RO_ALIGNMENT);
+    Image$$PT_RO_END$$Base = .;
+
+    /**** Base address of secure data area */
+    .tfm_secure_data_start :
+    {
+        /* Relocate current position to RAM */
+        . = ALIGN(4);
+    } > RAM
+
+    /*
+     * MPU on Armv6-M/v7-M core in multi-core topology may require more strict
+     * alignment that MPU region base address must align with the MPU region
+     * size.
+     * As a result, on Armv6-M/v7-M cores, to save memory resource and MPU
+     * regions, unprivileged data sections and privileged data sections are
+     * separated and gathered in unprivileged/privileged data area respectively.
+     * Keep BL2 shared data and MSP stack at the beginning of the secure data
+     * area on Armv8-M cores, while move the two areas to the beginning of
+     * privileged data region on Armv6-M/v7-M cores.
+     */
+#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) || \
+    defined(__ARM_ARCH_8_1M_MAIN__)
+#ifdef CODE_SHARING
+    /* The code sharing between bootloader and runtime requires to share the
+     * global variables.
+     */
+    .TFM_SHARED_SYMBOLS ALIGN(TFM_LINKER_SHARED_SYMBOLS_ALIGNMENT) :
+    {
+        . += SHARED_SYMBOL_AREA_SIZE;
+    } > RAM
+#endif
+
+    /* shared_data and msp_stack are overlapping on purpose when
+     * msp_stack is extended until the beginning of RAM, when shared_date
+     * was read out by partitions
+     */
+    .tfm_bl2_shared_data ALIGN(TFM_LINKER_BL2_SHARED_DATA_ALIGNMENT) :
+    {
+        . += BOOT_TFM_SHARED_DATA_SIZE;
+    } > RAM
+
+    .msp_stack ALIGN(TFM_LINKER_MSP_STACK_ALIGNMENT) :
+    {
+        . += __msp_stack_size__ - 0x8;
+    } > RAM
+    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
+    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
+
+    .msp_stack_seal_res :
+    {
+        . += 0x8;
+    } > RAM
+    __StackSeal = ADDR(.msp_stack_seal_res);
+
+#endif /* defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) || \
+        * defined(__ARM_ARCH_8_1M_MAIN__) */
+
+   .ram_vector_table (NOLOAD): ALIGN(256) {
+        *(.ram_vector_table)
+    } > RAM
+
+#if defined(ENABLE_HEAP)
+    __heap_size__ = S_HEAP_SIZE;
+    .heap (NOLOAD): ALIGN(8)
+    {
+        . = ALIGN(8);
+        __end__ = .;
+        end = __end__;
+        PROVIDE(end = .);
+        __HeapBase = .;
+        KEEP(*(.heap*))
+        . += __heap_size__;
+        __HeapLimit = .;
+        __heap_limit = .;
+    } > RAM
+#else
+    end = 0;
+#endif
+
+#if defined(CONFIG_TFM_PARTITION_META)
+    .TFM_SP_META_PTR ALIGN(TFM_LINKER_SP_META_PTR_ALIGNMENT) (NOLOAD):
+    {
+        *(.bss.SP_META_PTR_SPRTL_INST)
+        . = ALIGN(TFM_LINKER_SP_META_PTR_ALIGNMENT);
+    } > RAM
+    Image$$TFM_SP_META_PTR$$ZI$$Base = ADDR(.TFM_SP_META_PTR);
+    Image$$TFM_SP_META_PTR$$ZI$$Limit = ADDR(.TFM_SP_META_PTR) + SIZEOF(.TFM_SP_META_PTR);
+    /* This is needed for the uniform configuration of MPU region. */
+    Image$$TFM_SP_META_PTR_END$$ZI$$Limit = Image$$TFM_SP_META_PTR$$ZI$$Limit;
+#endif
+
+    /**** APPLICATION RoT DATA start here */
+    . = ALIGN(TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT);
+    Image$$TFM_APP_RW_STACK_START$$Base = .;
+
+    .TFM_APP_ROT_LINKER_DATA ALIGN(TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT) :
+    {
+        *tfm_app_rot_partition*:(SORT_BY_ALIGNMENT(.data*))
+        *(TFM_*_APP-ROT_ATTR_RW)
+        . = ALIGN(4);
+    } > RAM AT> FLASH
+    Image$$TFM_APP_ROT_LINKER_DATA$$RW$$Base = ADDR(.TFM_APP_ROT_LINKER_DATA);
+    Image$$TFM_APP_ROT_LINKER_DATA$$RW$$Limit = ADDR(.TFM_APP_ROT_LINKER_DATA) + SIZEOF(.TFM_APP_ROT_LINKER_DATA);
+
+    .TFM_APP_ROT_LINKER_BSS ALIGN(4) (NOLOAD) :
+    {
+        start_of_TFM_APP_ROT_LINKER = .;
+        *tfm_app_rot_partition*:(SORT_BY_ALIGNMENT(.bss*))
+        *tfm_app_rot_partition*:*(COMMON)
+        *(TFM_*_APP-ROT_ATTR_ZI)
+        . += (. - start_of_TFM_APP_ROT_LINKER) ? 0 : 4;
+        . = ALIGN(TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT);
+    } > RAM AT> RAM
+    Image$$TFM_APP_ROT_LINKER_DATA$$ZI$$Base = ADDR(.TFM_APP_ROT_LINKER_BSS);
+    Image$$TFM_APP_ROT_LINKER_DATA$$ZI$$Limit = ADDR(.TFM_APP_ROT_LINKER_BSS) + SIZEOF(.TFM_APP_ROT_LINKER_BSS);
+
+    /**** APPLICATION RoT DATA end here */
+    Image$$TFM_APP_RW_STACK_END$$Base = .;
+
+    /**** PSA RoT DATA start here */
+
+    Image$$TFM_PSA_RW_STACK_START$$Base = .;
+
+    .TFM_PSA_ROT_LINKER_DATA ALIGN(TFM_LINKER_PSA_ROT_LINKER_DATA_ALIGNMENT) :
+    {
+        *tfm_psa_rot_partition*:(SORT_BY_ALIGNMENT(.data*))
+        *(TFM_*_PSA-ROT_ATTR_RW)
+        . = ALIGN(4);
+    } > RAM AT> FLASH
+    Image$$TFM_PSA_ROT_LINKER_DATA$$RW$$Base = ADDR(.TFM_PSA_ROT_LINKER_DATA);
+    Image$$TFM_PSA_ROT_LINKER_DATA$$RW$$Limit = ADDR(.TFM_PSA_ROT_LINKER_DATA) + SIZEOF(.TFM_PSA_ROT_LINKER_DATA);
+
+    .TFM_PSA_ROT_LINKER_BSS ALIGN(4) (NOLOAD) :
+    {
+        start_of_TFM_PSA_ROT_LINKER = .;
+        *tfm_psa_rot_partition*:(SORT_BY_ALIGNMENT(.bss*))
+        *tfm_psa_rot_partition*:*(COMMON)
+        *(TFM_*_PSA-ROT_ATTR_ZI)
+        . += (. - start_of_TFM_PSA_ROT_LINKER) ? 0 : 4;
+        . = ALIGN(TFM_LINKER_PSA_ROT_LINKER_DATA_ALIGNMENT);
+    } > RAM AT> RAM
+    Image$$TFM_PSA_ROT_LINKER_DATA$$ZI$$Base = ADDR(.TFM_PSA_ROT_LINKER_BSS);
+    Image$$TFM_PSA_ROT_LINKER_DATA$$ZI$$Limit = ADDR(.TFM_PSA_ROT_LINKER_BSS) + SIZEOF(.TFM_PSA_ROT_LINKER_BSS);
+
+    /**** PSA RoT DATA end here */
+    Image$$TFM_PSA_RW_STACK_END$$Base = .;
+
+#ifdef RAM_VECTORS_SUPPORT
+    .ramVectors ALIGN(TFM_LINKER_RAM_VECTORS_ALIGNMENT) (NOLOAD) :
+    {
+        __ram_vectors_start__ = .;
+        KEEP(*(.ram_vectors))
+        __ram_vectors_end__   = .;
+    } > RAM
+    .TFM_DATA __ram_vectors_end__ :
+#else
+
+    .TFM_DATA ALIGN(4) :
+#endif
+    {
+        *(vtable)
+        *(.time_critical*)
+        *(*libplatform_s*:*Flash_RPI* .text*)
+        *(*libplatform_s*:*Flash_RPI* .rodata*)
+        *(SORT_BY_ALIGNMENT(.data*))
+        *(.sdata*)
+        . = ALIGN(4);
+        *(.after_data.*)
+
+        KEEP(*(.jcr*))
+        . = ALIGN(4);
+
+    } > RAM AT> FLASH
+    Image$$ER_TFM_DATA$$RW$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$RW$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA);
+
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM AT> RAM
+
+    .TFM_BSS ALIGN(4) (NOLOAD) :
+    {
+        __bss_start__ = .;
+
+        /* The runtime partition placed order is same as load partition */
+        __partition_runtime_start__ = .;
+        KEEP(*(.bss.part_runtime_priority_00))
+        KEEP(*(.bss.part_runtime_priority_01))
+        KEEP(*(.bss.part_runtime_priority_02))
+        KEEP(*(.bss.part_runtime_priority_03))
+        __partition_runtime_end__ = .;
+        . = ALIGN(4);
+
+        /* The runtime service placed order is same as load partition */
+        __service_runtime_start__ = .;
+        KEEP(*(.bss.serv_runtime_priority_00))
+        KEEP(*(.bss.serv_runtime_priority_01))
+        KEEP(*(.bss.serv_runtime_priority_02))
+        KEEP(*(.bss.serv_runtime_priority_03))
+        __service_runtime_end__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        *(.sbss*)
+        . = ALIGN(4);
+        __bss_end__ = .;
+    } > RAM AT> RAM
+    Image$$ER_TFM_DATA$$ZI$$Base = ADDR(.TFM_BSS);
+    Image$$ER_TFM_DATA$$ZI$$Limit = ADDR(.TFM_BSS) + SIZEOF(.TFM_BSS);
+    Image$$ER_PART_RT_POOL$$ZI$$Base = __partition_runtime_start__;
+    Image$$ER_PART_RT_POOL$$ZI$$Limit = __partition_runtime_end__;
+    Image$$ER_SERV_RT_POOL$$ZI$$Base = __service_runtime_start__;
+    Image$$ER_SERV_RT_POOL$$ZI$$Limit = __service_runtime_end__;
+
+    Image$$ER_TFM_DATA$$Base = ADDR(.TFM_DATA);
+    Image$$ER_TFM_DATA$$Limit = ADDR(.TFM_DATA) + SIZEOF(.TFM_DATA) + SIZEOF(.TFM_BSS);
+
+#if defined(CONFIG_TFM_USE_TRUSTZONE)
+    Image$$ER_VENEER$$Base = ADDR(.gnu.sgstubs);
+    Image$$VENEER_ALIGN$$Limit = ADDR(.sgstubs_end);
+
+#if defined(TFM_LINKER_VENEERS_SIZE)
+    ASSERT ((Image$$VENEER_ALIGN$$Limit - Image$$ER_VENEER$$Base) <= TFM_LINKER_VENEERS_SIZE, "Veneer region overflowed")
+#endif
+#endif
+
+    Load$$LR$$LR_NS_PARTITION$$Base = NS_PARTITION_START;
+
+#ifdef BL2
+    Load$$LR$$LR_SECONDARY_PARTITION$$Base = SECONDARY_PARTITION_START;
+#endif /* BL2 */
+
+    PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
+
+#ifdef __ENABLE_SCRATCH__
+    /* Start and end symbols must be word-aligned */
+    .scratch_x : {
+        __scratch_x_start__ = .;
+        *(.scratch_x.*)
+        . = ALIGN(4);
+        __scratch_x_end__ = .;
+    } > SCRATCH_X AT > FLASH
+    __scratch_x_source__ = LOADADDR(.scratch_x);
+    .scratch_y : {
+        __scratch_y_start__ = .;
+        *(.scratch_y.*)
+        . = ALIGN(4);
+        __scratch_y_end__ = .;
+    } > SCRATCH_Y AT > FLASH
+    __scratch_y_source__ = LOADADDR(.scratch_y);
+
+    .stack1_dummy (NOLOAD):
+    {
+        *(.stack1*)
+    } > SCRATCH_X
+    .stack_dummy (NOLOAD):
+    {
+        KEEP(*(.stack*))
+    } > SCRATCH_Y
+
+    PROVIDE(__StackBottom = Image$$ARM_LIB_STACK$$ZI$$Base);
+    PROVIDE(__StackTop = Image$$ARM_LIB_STACK$$ZI$$Limit);
+    __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+    __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+#endif
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary")
+}
diff --git a/platform/ext/target/rpi/rp2350/mbedtls_extra_config.h b/platform/ext/target/rpi/rp2350/mbedtls_extra_config.h
new file mode 100644
index 0000000..0d29541
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/mbedtls_extra_config.h
@@ -0,0 +1,11 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#undef MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG 1
+
+#define PSA_WANT_ALG_GCM 1
+
diff --git a/platform/ext/target/rpi/rp2350/ns/CMakeLists.txt b/platform/ext/target/rpi/rp2350/ns/CMakeLists.txt
new file mode 100644
index 0000000..7de958b
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/ns/CMakeLists.txt
@@ -0,0 +1,177 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+
+# initialize pico-sdk from GIT
+set(PICO_SDK_FETCH_FROM_GIT on)
+set(PICO_PLATFORM rp2350-arm-s)
+set(SKIP_BOOT_STAGE2 1)
+
+# initialize the Raspberry Pi Pico SDK
+include(${CMAKE_CURRENT_LIST_DIR}/pico_sdk_import.cmake)
+pico_sdk_init()
+
+get_target_property(pico_link_options pico_standard_link INTERFACE_LINK_OPTIONS)
+list(FILTER pico_link_options EXCLUDE REGEX "LINKER.*--script")
+list(APPEND pico_link_options "--entry=_entry_point")
+set_target_properties(pico_standard_link PROPERTIES INTERFACE_LINK_OPTIONS "${pico_link_options}")
+set_target_properties(pico_runtime PROPERTIES INTERFACE_LINK_OPTIONS "")
+
+
+cmake_policy(SET CMP0076 NEW)
+
+set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR})
+set(STATIC_ASSERT_OVERRIDE_HEADER "${PLATFORM_DIR}/static_assert_override.h")
+
+add_library(static_assert_override INTERFACE)
+add_library(device_definition INTERFACE)
+add_library(platform_ns STATIC)
+
+target_link_options(tfm_ns PRIVATE "LINKER:--no-warn-rwx-segments;LINKER:--entry=_entry_point")
+
+add_library(platform_ns_init INTERFACE)
+target_sources(platform_ns_init
+    INTERFACE
+        extra_init_ns.c
+)
+
+target_link_libraries(platform_ns_init
+    INTERFACE
+        cmsis_core_headers
+        pico_runtime_init
+        pico_runtime_headers
+        static_assert_override
+        pico_bootrom_headers
+        hardware_clocks
+)
+
+target_compile_definitions(platform_ns_init
+    INTERFACE
+        $<$<BOOL:${TFM_MULTI_CORE_TOPOLOGY}>:TFM_MULTI_CORE_TOPOLOGY>
+)
+
+# Note: This should be Private and in tfm_ns_scatter
+target_compile_definitions(platform_region_defs
+    INTERFACE
+        # u modifier in scatter file is not valid
+        NO_U_MODIFIER=1
+)
+#========================= Platform region defs ===============================#
+
+target_include_directories(platform_region_defs
+    INTERFACE
+        partition
+        ${CMAKE_CURRENT_SOURCE_DIR}
+        ${PLATFORM_DIR}/include
+        ${PLATFORM_DIR}/device/config
+)
+
+target_link_libraries(platform_region_defs
+    INTERFACE
+        hardware_regs_headers
+        static_assert_override
+)
+
+target_compile_options(static_assert_override
+    INTERFACE
+        "$<$<C_COMPILER_ID:Armclang>:SHELL:-include ${STATIC_ASSERT_OVERRIDE_HEADER}>"
+        "$<$<C_COMPILER_ID:GNU>:SHELL:-include ${STATIC_ASSERT_OVERRIDE_HEADER}>"
+        "$<$<C_COMPILER_ID:IAR>:SHELL:--preinclude ${STATIC_ASSERT_OVERRIDE_HEADER}>"
+)
+
+#========================= Device definition lib ===============================#
+
+target_include_directories(device_definition
+    INTERFACE
+        .
+        device/include
+        native_drivers
+        partition
+        libraries
+        native_drivers
+        ${PLATFORM_DIR}/ext/target/arm/drivers/flash/common
+        ${PLATFORM_DIR}/ext/target/arm/drivers/usart/cmsdk
+        ${PLATFORM_DIR}/ext/target/arm/drivers/usart/common
+        ${PLATFORM_DIR}/ext/target/arm/drivers/mpc_sie
+        ${PLATFORM_DIR}/ext/target/arm/drivers/mpu/armv8m
+        ${PLATFORM_DIR}/ext/target/arm/drivers/counter/armv8m
+        ${PLATFORM_DIR}/ext/target/arm/drivers/timer/armv8m
+        ${ETHOS_DRIVER_PATH}/src
+        ${ETHOS_DRIVER_PATH}/include
+        ${CMAKE_CURRENT_SOURCE_DIR}/device/config
+)
+
+#========================= Platform Non-Secure ================================#
+
+target_sources(platform_ns
+    PRIVATE
+        $<$<BOOL:${TFM_NS_MAILBOX_API}>:platform_ns_mailbox.c>
+        cmsis_drivers/Driver_USART_RPI.c
+        ${PLATFORM_DIR}/ext/target/arm/drivers/usart/cmsdk/uart_cmsdk_drv.c
+)
+
+target_include_directories(platform_ns
+    PUBLIC
+        cmsis_drivers
+        ${PLATFORM_DIR}/ext/cmsis/Include
+        ${PLATFORM_DIR}/ext/cmsis/Include/m-profile
+        ${PLATFORM_DIR}/include
+        ${PLATFORM_DIR}/ext/common
+)
+
+target_link_libraries(platform_ns
+    PUBLIC
+        cmsis_core_headers
+        platform_ns_init
+    PRIVATE
+        device_definition
+        pico_crt0
+        $<$<BOOL:${TFM_MULTI_CORE_TOPOLOGY}>:pico_multicore>
+        hardware_regs
+        hardware_flash
+        hardware_uart
+        cmsis_core
+)
+
+target_compile_definitions(platform_ns
+    PUBLIC
+        PICO_UART_DEFAULT_CRLF=1
+        CMSIS_device_header=<RP2350.h>
+        PICO_DEFAULT_TIMER=1
+        $<$<BOOL:${TFM_MULTI_CORE_TOPOLOGY}>:TFM_MULTI_CORE_TOPOLOGY>
+)
+
+if (TFM_NS_CUSTOM_API)
+    target_sources(tfm_api_ns PRIVATE
+        ${INTERFACE_SRC_DIR}/os_wrapper/tfm_ns_interface_rtos.c
+    )
+
+    add_library(tfm_api_ns_custom INTERFACE)
+
+    target_sources(tfm_api_ns_custom
+        INTERFACE
+            tfm_custom_psa_ns_api.c
+    )
+
+    target_link_libraries(tfm_api_ns_custom
+        INTERFACE
+            ${INTERFACE_SRC_DIR}/../lib/s_veneers.o
+    )
+
+    target_link_libraries(tfm_api_ns
+        PRIVATE
+            tfm_api_ns_custom
+            os_wrapper
+    )
+
+    # lib parth
+    set(APP_LIB_DIR                  ${CMAKE_CURRENT_LIST_DIR}/../../../../../lib)
+
+    target_sources(RTX_OS
+        INTERFACE
+            # Provide TZ context management stub to RTOS if protected by Trustzone
+            ${APP_LIB_DIR}/nsid_manager/tz_shim_layer.c
+    )
+endif()
diff --git a/platform/ext/target/rpi/rp2350/ns/extra_init_ns.c b/platform/ext/target/rpi/rp2350/ns/extra_init_ns.c
new file mode 100644
index 0000000..0941ece
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/ns/extra_init_ns.c
@@ -0,0 +1,84 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "hardware/clocks.h"
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+#include "hardware/structs/sio.h"
+#include "hardware/structs/scb.h"
+#include "tfm_multi_core_api.h"
+#endif
+
+#include "stdint.h"
+
+/* Do not use __cmsis_start */
+#define __PROGRAM_START
+#include "tfm_hal_device_header.h"
+
+void copy_zero_tables(void) {
+    typedef struct {
+        uint32_t const* src;
+        uint32_t* dest;
+        uint32_t  wlen;
+    } __copy_table_t;
+
+    typedef struct {
+        uint32_t* dest;
+        uint32_t  wlen;
+    } __zero_table_t;
+
+    extern const __copy_table_t __copy_table_start__;
+    extern const __copy_table_t __copy_table_end__;
+    extern const __zero_table_t __zero_table_start__;
+    extern const __zero_table_t __zero_table_end__;
+
+    for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {
+        for(uint32_t i=0u; i<pTable->wlen; ++i) {
+            pTable->dest[i] = pTable->src[i];
+        }
+    }
+
+    for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {
+        for(uint32_t i=0u; i<pTable->wlen; ++i) {
+            pTable->dest[i] = 0u;
+        }
+    }
+}
+
+void __weak hard_assertion_failure(void) {
+    panic("Hard assert");
+}
+
+extern void runtime_init_install_ram_vector_table(void);
+extern uint32_t ram_vector_table[PICO_RAM_VECTOR_TABLE_SIZE];
+
+void runtime_init(void) {
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    if(sio_hw->cpuid == 0) {
+        scb_hw->vtor = (uintptr_t) ram_vector_table;
+        return;
+    }
+#endif
+    copy_zero_tables();
+    runtime_init_install_ram_vector_table();
+
+    /* These are already configured by the Secure side, just fill the array */
+    clock_set_reported_hz(clk_ref, XOSC_KHZ * KHZ);
+    clock_set_reported_hz(clk_sys, SYS_CLK_KHZ * KHZ);
+    clock_set_reported_hz(clk_peri, SYS_CLK_KHZ * KHZ);
+    clock_set_reported_hz(clk_hstx, SYS_CLK_KHZ * KHZ);
+    clock_set_reported_hz(clk_usb, USB_CLK_KHZ * KHZ);
+    clock_set_reported_hz(clk_adc, USB_CLK_KHZ * KHZ);
+
+    SystemInit();
+}
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+int32_t tfm_ns_wait_for_s_cpu_ready(void)
+{
+    return tfm_platform_ns_wait_for_s_cpu_ready();
+}
+#endif
diff --git a/platform/ext/target/rpi/rp2350/ns/platform_ns_mailbox.c b/platform/ext/target/rpi/rp2350/ns/platform_ns_mailbox.c
new file mode 100644
index 0000000..469eacf
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/ns/platform_ns_mailbox.c
@@ -0,0 +1,154 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+/* FIXME: This shouldn't be required when TFM_PLAT_SPECIFIC_MULTI_CORE_COMM is
+ * enabled.
+ */
+
+#include "tfm_ns_mailbox.h"
+#include "platform_multicore.h"
+#include "region.h"
+
+#include "pico/multicore.h"
+#include "hardware/irq.h"
+#include "hardware/structs/scb.h"
+#include "hardware/structs/sio.h"
+
+#include "tfm_hal_device_header.h"
+#include "uart_stdout.h"
+#include "Driver_Common.h"
+
+int32_t tfm_ns_platform_init(void)
+{
+    if(sio_hw->cpuid == 0) {
+        __enable_irq();
+    } else {
+        /* Core1 */
+        __enable_irq();
+        stdio_init();
+    }
+
+    return ARM_DRIVER_OK;
+}
+
+/* Platform specific inter-processor communication interrupt handler. */
+void SIO_IRQ_FIFO_NS_IRQHandler(void)
+{
+    uint32_t msg;
+    if(multicore_fifo_rvalid())
+    {
+        msg = multicore_fifo_pop_blocking();
+        if (msg == NOTIFY_FROM_CORE0) {
+            /* Handle all the pending replies */
+            tfm_ns_mailbox_wake_reply_owner_isr();
+        }
+    }
+}
+
+int32_t tfm_ns_mailbox_hal_init(struct ns_mailbox_queue_t *queue)
+{
+    uint32_t stage;
+
+    if(sio_hw->cpuid == 0) {
+        return MAILBOX_SUCCESS;
+    }
+
+    if (!queue) {
+        return MAILBOX_INVAL_PARAMS;
+    }
+
+    NVIC_SetVector(SIO_IRQ_FIFO_NS_IRQn, (uint32_t) SIO_IRQ_FIFO_NS_IRQHandler);
+
+    /*
+     * Wait until SPE mailbox library is ready to receive NSPE mailbox queue
+     * address.
+     */
+    while (1) {
+        stage = multicore_fifo_pop_blocking();
+        if  (stage == NS_MAILBOX_INIT) {
+            break;
+        }
+    }
+
+    /* Send out the address */
+    struct mailbox_init_t ns_init;
+    ns_init.status = &queue->status;
+    ns_init.slot_count = NUM_MAILBOX_QUEUE_SLOT;
+    ns_init.slots = &queue->slots[0];
+    multicore_fifo_push_blocking((uint32_t) &ns_init);
+
+    /* Wait until SPE mailbox service is ready */
+    while (1) {
+        stage = multicore_fifo_pop_blocking();
+        if  (stage == S_MAILBOX_READY) {
+            break;
+        }
+    }
+
+    NVIC_EnableIRQ(SIO_IRQ_FIFO_NS_IRQn);
+
+    return MAILBOX_SUCCESS;
+}
+
+int32_t tfm_ns_mailbox_hal_notify_peer(void)
+{
+    multicore_fifo_push_blocking(NOTIFY_FROM_CORE1);
+    return 0;
+}
+
+void tfm_ns_mailbox_hal_enter_critical(void)
+{
+    /* Reading a spinlock register attempts to claim it, returning nonzero
+     * if the claim was successful and 0 if unsuccessful */
+    while(!*MAILBOX_SPINLOCK);
+    return;
+}
+
+void tfm_ns_mailbox_hal_exit_critical(void)
+{
+    /* Writing to a spinlock register releases it */
+    *MAILBOX_SPINLOCK = 0x1u;
+    return;
+}
+
+void tfm_ns_mailbox_hal_enter_critical_isr(void)
+{
+    /* Reading a spinlock register attempts to claim it, returning nonzero
+     * if the claim was successful and 0 if unsuccessful */
+    while(!*MAILBOX_SPINLOCK);
+    return;
+}
+
+void tfm_ns_mailbox_hal_exit_critical_isr(void)
+{
+    /* Writing to a spinlock register releases it */
+    *MAILBOX_SPINLOCK = 0x1u;
+    return;
+}
+
+extern void runtime_init(void);
+extern int main(void);
+extern uint32_t __StackOneTop;
+extern uint32_t __Vectors_Start__;
+
+void __attribute__((section(".core1_ns_entry"), used, naked)) core1_ns_entry(void)
+{
+    scb_hw->vtor = (uintptr_t) &__Vectors_Start__;
+    __set_MSP((uint32_t)(&__StackOneTop));
+    __set_PSP((uint32_t)(&__StackOneTop));
+    runtime_init();
+    main();
+}
+
+#include "stdio.h"
+int32_t tfm_platform_ns_wait_for_s_cpu_ready(void)
+{
+    if(sio_hw->cpuid == 1) {
+        /* Core1 */
+        multicore_fifo_push_blocking(CORE1_NS_READY);
+    }
+    return 0;
+}
diff --git a/platform/ext/target/rpi/rp2350/ns/tfm_custom_psa_ns_api.c b/platform/ext/target/rpi/rp2350/ns/tfm_custom_psa_ns_api.c
new file mode 100644
index 0000000..3d45f5a
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/ns/tfm_custom_psa_ns_api.c
@@ -0,0 +1,234 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "psa/client.h"
+#include "tfm_ns_interface.h"
+#include "tfm_psa_call_pack.h"
+#include "tfm_mailbox.h"
+#include "tfm_ns_mailbox.h"
+
+#include "hardware/structs/sio.h"
+
+/*
+ * TODO
+ * Currently, force all the non-secure client to share the same ID.
+ *
+ * It requires a more clear mechanism to synchronize the non-secure client
+ * ID with SPE in dual core scenario.
+ * In current design, the value is transferred to SPE via mailbox message.
+ * A dedicated routine to receive the non-secure client information in
+ * TF-M core/SPM in dual core scenario should be added besides current
+ * implementation for single Armv8-M.
+ * The non-secure client identification is shared with SPE in
+ * single Armv8-M scenario via CMSIS TrustZone context management API,
+ * which may not work in dual core scenario.
+ */
+#define NON_SECURE_CLIENT_ID            (-1)
+
+/*
+ * TODO
+ * Require a formal definition of errors related to mailbox in PSA client call.
+ */
+#define PSA_INTER_CORE_COMM_ERR         (INT32_MIN + 0xFF)
+
+/**** TZ API functions ****/
+
+uint32_t tz_psa_framework_version(void)
+{
+    return tfm_ns_interface_dispatch(
+                                (veneer_fn)tfm_psa_framework_version_veneer,
+                                0,
+                                0,
+                                0,
+                                0);
+}
+
+uint32_t tz_psa_version(uint32_t sid)
+{
+    return tfm_ns_interface_dispatch(
+                                (veneer_fn)tfm_psa_version_veneer,
+                                sid,
+                                0,
+                                0,
+                                0);
+}
+
+psa_status_t tz_psa_call(psa_handle_t handle, int32_t type,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len)
+{
+    if ((type    > PSA_CALL_TYPE_MAX) ||
+        (type    < PSA_CALL_TYPE_MIN) ||
+        (in_len  > PSA_MAX_IOVEC)     ||
+        (out_len > PSA_MAX_IOVEC)) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    return tfm_ns_interface_dispatch(
+                                (veneer_fn)tfm_psa_call_veneer,
+                                (uint32_t)handle,
+                                PARAM_PACK(type, in_len, out_len),
+                                (uint32_t)in_vec,
+                                (uint32_t)out_vec);
+}
+
+psa_handle_t tz_psa_connect(uint32_t sid, uint32_t version)
+{
+    return tfm_ns_interface_dispatch((veneer_fn)tfm_psa_connect_veneer, sid, version, 0, 0);
+}
+
+void tz_psa_close(psa_handle_t handle)
+{
+    (void)tfm_ns_interface_dispatch((veneer_fn)tfm_psa_close_veneer, (uint32_t)handle, 0, 0, 0);
+}
+
+/**** Mailbox API functions ****/
+
+uint32_t mb_psa_framework_version(void)
+{
+    struct psa_client_params_t params;
+    uint32_t version;
+    int32_t ret;
+
+    ret = tfm_ns_mailbox_client_call(MAILBOX_PSA_FRAMEWORK_VERSION,
+                                     &params, NON_SECURE_CLIENT_ID,
+                                     (int32_t *)&version);
+    if (ret != MAILBOX_SUCCESS) {
+        version = PSA_VERSION_NONE;
+    }
+
+    return version;
+}
+
+uint32_t mb_psa_version(uint32_t sid)
+{
+    struct psa_client_params_t params;
+    uint32_t version;
+    int32_t ret;
+
+    params.psa_version_params.sid = sid;
+
+    ret = tfm_ns_mailbox_client_call(MAILBOX_PSA_VERSION, &params,
+                                     NON_SECURE_CLIENT_ID,
+                                     (int32_t *)&version);
+    if (ret != MAILBOX_SUCCESS) {
+        version = PSA_VERSION_NONE;
+    }
+
+    return version;
+}
+
+psa_handle_t mb_psa_connect(uint32_t sid, uint32_t version)
+{
+    struct psa_client_params_t params;
+    psa_handle_t psa_handle;
+    int32_t ret;
+
+    params.psa_connect_params.sid = sid;
+    params.psa_connect_params.version = version;
+
+    ret = tfm_ns_mailbox_client_call(MAILBOX_PSA_CONNECT, &params,
+                                     NON_SECURE_CLIENT_ID,
+                                     (int32_t *)&psa_handle);
+    if (ret != MAILBOX_SUCCESS) {
+        psa_handle = PSA_NULL_HANDLE;
+    }
+
+    return psa_handle;
+}
+
+psa_status_t mb_psa_call(psa_handle_t handle, int32_t type,
+                      const psa_invec *in_vec, size_t in_len,
+                      psa_outvec *out_vec, size_t out_len)
+{
+    struct psa_client_params_t params;
+    int32_t ret;
+    psa_status_t status;
+
+    params.psa_call_params.handle = handle;
+    params.psa_call_params.type = type;
+    params.psa_call_params.in_vec = in_vec;
+    params.psa_call_params.in_len = in_len;
+    params.psa_call_params.out_vec = out_vec;
+    params.psa_call_params.out_len = out_len;
+
+    ret = tfm_ns_mailbox_client_call(MAILBOX_PSA_CALL, &params,
+                                     NON_SECURE_CLIENT_ID,
+                                     (int32_t *)&status);
+    if (ret != MAILBOX_SUCCESS) {
+        status = PSA_INTER_CORE_COMM_ERR;
+    }
+
+    return status;
+}
+
+void mb_psa_close(psa_handle_t handle)
+{
+    struct psa_client_params_t params;
+    int32_t reply;
+
+    params.psa_close_params.handle = handle;
+
+    (void)tfm_ns_mailbox_client_call(MAILBOX_PSA_CLOSE, &params,
+                                     NON_SECURE_CLIENT_ID, &reply);
+}
+
+/**** API functions ****/
+
+uint32_t psa_framework_version(void)
+{
+    if(sio_hw->cpuid == 0) {
+        return tz_psa_framework_version();
+    } else {
+        return mb_psa_framework_version();
+    }
+}
+
+uint32_t psa_version(uint32_t sid)
+{
+    if(sio_hw->cpuid == 0) {
+        return tz_psa_version(sid);
+    } else {
+        return mb_psa_version(sid);
+    }
+}
+
+psa_status_t psa_call(psa_handle_t handle, int32_t type,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len)
+{
+    if(sio_hw->cpuid == 0) {
+        return tz_psa_call(handle, type, in_vec, in_len, out_vec, out_len);
+    } else {
+        return mb_psa_call(handle, type, in_vec, in_len, out_vec, out_len);
+    }
+}
+
+psa_handle_t psa_connect(uint32_t sid, uint32_t version)
+{
+    if(sio_hw->cpuid == 0) {
+        return tz_psa_connect(sid, version);
+    } else {
+        return mb_psa_connect(sid, version);
+    }
+}
+
+void psa_close(psa_handle_t handle)
+{
+    if(sio_hw->cpuid == 0) {
+        return tz_psa_close(handle);
+    } else {
+        return mb_psa_close(handle);
+    }
+}
diff --git a/platform/ext/target/rpi/rp2350/nv_counters.c b/platform/ext/target/rpi/rp2350/nv_counters.c
new file mode 100644
index 0000000..fcab604
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/nv_counters.c
@@ -0,0 +1,168 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_plat_nv_counters.h"
+#include "tfm_plat_otp.h"
+
+#include <limits.h>
+#include <string.h>
+
+#define OTP_COUNTER_MAX_SIZE    64
+#define NV_COUNTER_SIZE         4
+#define OTP_COUNTER_MAGIC       0xAEC7
+
+enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
+{
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+static enum tfm_plat_err_t read_otp_counter(enum tfm_otp_element_id_t id,
+                                            uint8_t *val)
+{
+    size_t counter_size;
+    enum tfm_plat_err_t err;
+    size_t idx;
+    uint16_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint16_t)] = {0};
+    uint32_t count;
+
+    err = tfm_plat_otp_get_size(id, &counter_size);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
+                                                       : counter_size;
+
+    err = tfm_plat_otp_read(id, counter_size, (uint8_t *)counter_value);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    count = 0;
+    for (idx = 0; idx < counter_size / sizeof(uint16_t); idx++) {
+        if (counter_value[idx] == OTP_COUNTER_MAGIC) {
+            count += 1;
+        } else if (counter_value[idx] == 0) {
+            break;
+        } else {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    memcpy(val, &count, NV_COUNTER_SIZE);
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
+                                             uint32_t size, uint8_t *val)
+{
+    if (size != NV_COUNTER_SIZE) {
+        return TFM_PLAT_ERR_INVALID_INPUT;
+    }
+
+    /* Assumes Platform nv counters are contiguous*/
+    if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
+        counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
+                                       (counter_id - PLAT_NV_COUNTER_BL2_0),
+                                   val);
+    }
+
+    switch (counter_id) {
+    case (PLAT_NV_COUNTER_NS_0):
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
+    case (PLAT_NV_COUNTER_NS_1):
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
+    case (PLAT_NV_COUNTER_NS_2):
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
+    case (PLAT_NV_COUNTER_PS_0):
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
+    case (PLAT_NV_COUNTER_PS_1):
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
+    case (PLAT_NV_COUNTER_PS_2):
+        return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
+
+    default:
+        return TFM_PLAT_ERR_UNSUPPORTED;
+    }
+}
+
+static enum tfm_plat_err_t set_otp_counter(enum tfm_otp_element_id_t id,
+                                           uint32_t val)
+{
+    size_t counter_size;
+    enum tfm_plat_err_t err;
+    size_t idx;
+    uint16_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint16_t)] = {0};
+
+    err = tfm_plat_otp_get_size(id, &counter_size);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
+                                                       : counter_size;
+
+    if (val > (counter_size / sizeof(uint16_t))) {
+        return TFM_PLAT_ERR_INVALID_INPUT;
+    }
+
+    for (idx = 0; idx < val; idx++) {
+        counter_value[idx] = OTP_COUNTER_MAGIC;
+    }
+
+    err = tfm_plat_otp_write(id, counter_size,
+                             (uint8_t *)counter_value);
+
+    return err;
+}
+
+enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
+                                            uint32_t value)
+{
+    /* Assumes Platform nv counters are contiguous*/
+    if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
+        counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
+                                      (counter_id - PLAT_NV_COUNTER_BL2_0),
+                                  value);
+    }
+
+    switch (counter_id) {
+    case (PLAT_NV_COUNTER_NS_0):
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
+    case (PLAT_NV_COUNTER_NS_1):
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
+    case (PLAT_NV_COUNTER_NS_2):
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
+    case (PLAT_NV_COUNTER_PS_0):
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
+    case (PLAT_NV_COUNTER_PS_1):
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
+    case (PLAT_NV_COUNTER_PS_2):
+        return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
+
+    default:
+        return TFM_PLAT_ERR_UNSUPPORTED;
+    }
+}
+
+enum tfm_plat_err_t tfm_plat_increment_nv_counter(
+                                           enum tfm_nv_counter_t counter_id)
+{
+    uint32_t security_cnt;
+    enum tfm_plat_err_t err;
+
+    err = tfm_plat_read_nv_counter(counter_id,
+                                   sizeof(security_cnt),
+                                   (uint8_t *)&security_cnt);
+    if (err != TFM_PLAT_ERR_SUCCESS) {
+        return err;
+    }
+
+    return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
+}
diff --git a/platform/ext/target/rpi/rp2350/partition/flash_layout.h b/platform/ext/target/rpi/rp2350/partition/flash_layout.h
new file mode 100644
index 0000000..6e982ea
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/partition/flash_layout.h
@@ -0,0 +1,203 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __FLASH_LAYOUT_H__
+#define __FLASH_LAYOUT_H__
+
+#include "hardware/regs/addressmap.h" /* Coming from SDK */
+
+
+#define FLASH_S_PARTITION_SIZE     (0x3C000)    /* 240 kB */
+#define FLASH_NS_PARTITION_SIZE    (0x2F000)    /* 188 kB */
+
+#define FLASH_MAX_PARTITION_SIZE FLASH_S_PARTITION_SIZE
+
+/* Sector size of the flash hardware; same as FLASH0_SECTOR_SIZE */
+#define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x1000)        /* 4 kB */
+/* Same as FLASH0_SIZE */
+#define FLASH_TOTAL_SIZE                (0x200000)      /* 2MB */
+
+#if ((FLASH_S_PARTITION_SIZE % FLASH_AREA_IMAGE_SECTOR_SIZE) != 0)
+#error "Secure image size should be a multiple of flash sector size!"
+#endif
+
+#if ((FLASH_NS_PARTITION_SIZE % FLASH_AREA_IMAGE_SECTOR_SIZE) != 0)
+#error "Non-secure image size should be a multiple of flash sector size!"
+#endif
+
+/* Flash layout info for BL2 bootloader */
+#define FLASH_BASE_ADDRESS              (XIP_BASE)
+
+/* Offset and size definitions of the flash partitions that are handled by the
+ * bootloader. The image swapping is done between IMAGE_PRIMARY and
+ * IMAGE_SECONDARY, SCRATCH is used as a temporary storage during image
+ * swapping.
+ */
+#define FLASH_AREA_BL2_OFFSET      (0x0)
+#define FLASH_AREA_BL2_SIZE        (0x11000) /* 68 kB */
+
+#if !defined(MCUBOOT_IMAGE_NUMBER) || (MCUBOOT_IMAGE_NUMBER == 1)
+/* Secure + Non-secure image primary slot */
+#define FLASH_AREA_0_ID            (1)
+#define FLASH_AREA_0_OFFSET        (FLASH_AREA_BL2_OFFSET + FLASH_AREA_BL2_SIZE)
+#define FLASH_AREA_0_SIZE          (FLASH_S_PARTITION_SIZE + \
+                                    FLASH_NS_PARTITION_SIZE)
+/* Secure + Non-secure secondary slot */
+#define FLASH_AREA_2_ID            (FLASH_AREA_0_ID + 1)
+#define FLASH_AREA_2_OFFSET        (FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE)
+#define FLASH_AREA_2_SIZE          (FLASH_S_PARTITION_SIZE + \
+                                    FLASH_NS_PARTITION_SIZE)
+/* Scratch area */
+#define FLASH_AREA_SCRATCH_ID      (FLASH_AREA_2_ID + 1)
+#define FLASH_AREA_SCRATCH_OFFSET  (FLASH_AREA_2_OFFSET + FLASH_AREA_2_SIZE)
+#define FLASH_AREA_SCRATCH_SIZE    (0x8000) /* 32 kB */
+/* The maximum number of status entries supported by the bootloader. */
+#define MCUBOOT_STATUS_MAX_ENTRIES ((FLASH_S_PARTITION_SIZE + \
+                                     FLASH_NS_PARTITION_SIZE) / \
+                                    FLASH_AREA_SCRATCH_SIZE)
+/* Maximum number of image sectors supported by the bootloader. */
+#define MCUBOOT_MAX_IMG_SECTORS    ((FLASH_S_PARTITION_SIZE + \
+                                     FLASH_NS_PARTITION_SIZE) / \
+                                    FLASH_AREA_IMAGE_SECTOR_SIZE)
+#elif (MCUBOOT_IMAGE_NUMBER == 2)
+/* Secure image primary slot */
+#define FLASH_AREA_0_ID            (1)
+#define FLASH_AREA_0_OFFSET        (FLASH_AREA_BL2_OFFSET + FLASH_AREA_BL2_SIZE)
+#define FLASH_AREA_0_SIZE          (FLASH_S_PARTITION_SIZE)
+/* Non-secure image primary slot */
+#define FLASH_AREA_1_ID            (FLASH_AREA_0_ID + 1)
+#define FLASH_AREA_1_OFFSET        (FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE)
+#define FLASH_AREA_1_SIZE          (FLASH_NS_PARTITION_SIZE)
+/* Secure image secondary slot */
+#define FLASH_AREA_2_ID            (FLASH_AREA_1_ID + 1)
+#define FLASH_AREA_2_OFFSET        (FLASH_AREA_1_OFFSET + FLASH_AREA_1_SIZE)
+#define FLASH_AREA_2_SIZE          (FLASH_S_PARTITION_SIZE)
+/* Non-secure image secondary slot */
+#define FLASH_AREA_3_ID            (FLASH_AREA_2_ID + 1)
+#define FLASH_AREA_3_OFFSET        (FLASH_AREA_2_OFFSET + FLASH_AREA_2_SIZE)
+#define FLASH_AREA_3_SIZE          (FLASH_NS_PARTITION_SIZE)
+/* Scratch area */
+#define FLASH_AREA_SCRATCH_ID      (FLASH_AREA_3_ID + 1)
+#define FLASH_AREA_SCRATCH_OFFSET  (FLASH_AREA_3_OFFSET + FLASH_AREA_3_SIZE)
+#define FLASH_AREA_SCRATCH_SIZE    (0x8000) /* 32 kB */
+/* The maximum number of status entries supported by the bootloader. */
+#define MCUBOOT_STATUS_MAX_ENTRIES (FLASH_MAX_PARTITION_SIZE / \
+                                    FLASH_AREA_SCRATCH_SIZE)
+/* Maximum number of image sectors supported by the bootloader. */
+#define MCUBOOT_MAX_IMG_SECTORS    (FLASH_MAX_PARTITION_SIZE / \
+                                    FLASH_AREA_IMAGE_SECTOR_SIZE)
+#else /* MCUBOOT_IMAGE_NUMBER > 2 */
+#error "Only MCUBOOT_IMAGE_NUMBER 1 and 2 are supported!"
+#endif /* MCUBOOT_IMAGE_NUMBER */
+
+/* Protected Storage (PS) Service definitions */
+#define FLASH_PS_AREA_OFFSET            (FLASH_AREA_SCRATCH_OFFSET + \
+                                         FLASH_AREA_SCRATCH_SIZE)
+#define FLASH_PS_AREA_SIZE              (2 * FLASH_AREA_IMAGE_SECTOR_SIZE)   /* 8 kB */
+
+/* Internal Trusted Storage (ITS) Service definitions */
+#define FLASH_ITS_AREA_OFFSET           (FLASH_PS_AREA_OFFSET + \
+                                         FLASH_PS_AREA_SIZE)
+#define FLASH_ITS_AREA_SIZE             (2 * FLASH_AREA_IMAGE_SECTOR_SIZE)   /* 8 kB */
+
+/* OTP_definitions */
+#define FLASH_OTP_NV_COUNTERS_AREA_OFFSET (FLASH_ITS_AREA_OFFSET + \
+                                           FLASH_ITS_AREA_SIZE)
+#define FLASH_OTP_NV_COUNTERS_AREA_SIZE   (2 * FLASH_AREA_IMAGE_SECTOR_SIZE)   /* 8 kB */
+#define FLASH_OTP_NV_COUNTERS_SECTOR_SIZE FLASH_AREA_IMAGE_SECTOR_SIZE
+
+#if (((FLASH_OTP_NV_COUNTERS_AREA_SIZE % FLASH_AREA_IMAGE_SECTOR_SIZE) != 0) ||          \
+    (FLASH_OTP_NV_COUNTERS_AREA_SIZE < (2 * FLASH_OTP_NV_COUNTERS_SECTOR_SIZE)) ||       \
+    (((FLASH_OTP_NV_COUNTERS_AREA_SIZE / FLASH_OTP_NV_COUNTERS_SECTOR_SIZE) % 2) != 0)   \
+    )
+#error "NV_COUNTERS should be a multiple of block size and total number of blocks should be more greater than or equal to 2 and even."
+#endif
+
+#if ( FLASH_OTP_NV_COUNTERS_AREA_OFFSET + FLASH_OTP_NV_COUNTERS_AREA_SIZE > FLASH_TOTAL_SIZE)
+#error "Out of flash memory!"
+#endif
+
+/* Offset and size definition in flash area used by assemble.py */
+#define SECURE_IMAGE_OFFSET             (0x0)
+#define SECURE_IMAGE_MAX_SIZE           FLASH_S_PARTITION_SIZE
+
+#define NON_SECURE_IMAGE_OFFSET         (SECURE_IMAGE_OFFSET + \
+                                         SECURE_IMAGE_MAX_SIZE)
+#define NON_SECURE_IMAGE_MAX_SIZE       FLASH_NS_PARTITION_SIZE
+
+/* Flash device name used by BL2
+ * Name is defined in flash driver file: Driver_Flash_RPI.c
+ */
+#define FLASH_DEV_NAME RP2350_FLASH
+/* Smallest flash programmable unit in bytes */
+#define TFM_HAL_FLASH_PROGRAM_UNIT       (0x100)
+
+/* Protected Storage (PS) Service definitions
+ * Note: Further documentation of these definitions can be found in the
+ * TF-M PS Integration Guide.
+ */
+#define TFM_HAL_PS_FLASH_DRIVER RP2350_FLASH
+
+/* In this target the CMSIS driver requires only the offset from the base
+ * address instead of the full memory address.
+ */
+/* Base address of dedicated flash area for PS */
+#define TFM_HAL_PS_FLASH_AREA_ADDR    FLASH_PS_AREA_OFFSET
+/* Size of dedicated flash area for PS */
+#define TFM_HAL_PS_FLASH_AREA_SIZE    FLASH_PS_AREA_SIZE
+#define PS_RAM_FS_SIZE                TFM_HAL_PS_FLASH_AREA_SIZE
+/* Number of physical erase sectors per logical FS block */
+#define TFM_HAL_PS_SECTORS_PER_BLOCK  (1)
+/* Smallest flash programmable unit in bytes */
+#define TFM_HAL_PS_PROGRAM_UNIT       TFM_HAL_FLASH_PROGRAM_UNIT
+#define PS_FLASH_NAND_BUF_SIZE        (FLASH_AREA_IMAGE_SECTOR_SIZE)
+
+#if (((TFM_HAL_PS_FLASH_AREA_SIZE % FLASH_AREA_IMAGE_SECTOR_SIZE) != 0) ||   \
+    ((TFM_HAL_PS_FLASH_AREA_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE) == 0) ||   \
+    ((TFM_HAL_PS_FLASH_AREA_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE) == 1) ||   \
+    ((TFM_HAL_PS_FLASH_AREA_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE) == 3)      \
+    )
+#error "PS area size should be a multiple of block size and total number of blocks can not be 0, 1 or 3."
+#endif
+
+/* Internal Trusted Storage (ITS) Service definitions
+ * Note: Further documentation of these definitions can be found in the
+ * TF-M ITS Integration Guide. The ITS should be in the internal flash, but is
+ * allocated in the external flash just for development platforms that don't
+ * have internal flash available.
+ */
+#define TFM_HAL_ITS_FLASH_DRIVER RP2350_FLASH
+
+/* In this target the CMSIS driver requires only the offset from the base
+ * address instead of the full memory address.
+ */
+/* Base address of dedicated flash area for ITS */
+#define TFM_HAL_ITS_FLASH_AREA_ADDR    FLASH_ITS_AREA_OFFSET
+/* Size of dedicated flash area for ITS */
+#define TFM_HAL_ITS_FLASH_AREA_SIZE    FLASH_ITS_AREA_SIZE
+#define ITS_RAM_FS_SIZE                TFM_HAL_ITS_FLASH_AREA_SIZE
+/* Number of physical erase sectors per logical FS block */
+#define TFM_HAL_ITS_SECTORS_PER_BLOCK  (1)
+/* Smallest flash programmable unit in bytes */
+#define TFM_HAL_ITS_PROGRAM_UNIT       TFM_HAL_FLASH_PROGRAM_UNIT
+#define ITS_FLASH_NAND_BUF_SIZE        (2 * FLASH_AREA_IMAGE_SECTOR_SIZE)
+
+#if (((TFM_HAL_ITS_FLASH_AREA_SIZE % FLASH_AREA_IMAGE_SECTOR_SIZE) != 0) ||  \
+    ((TFM_HAL_ITS_FLASH_AREA_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE) == 0) ||   \
+    ((TFM_HAL_ITS_FLASH_AREA_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE) == 1) ||   \
+    ((TFM_HAL_ITS_FLASH_AREA_SIZE / FLASH_AREA_IMAGE_SECTOR_SIZE) == 3)      \
+    )
+#error "ITS area size should be a multiple of block size and total number of blocks can not be 0, 1 or 3."
+#endif
+
+/* OTP / NV counter definitions */
+#define TFM_OTP_NV_COUNTERS_AREA_SIZE   (FLASH_OTP_NV_COUNTERS_AREA_SIZE / 2)
+#define TFM_OTP_NV_COUNTERS_AREA_ADDR   FLASH_OTP_NV_COUNTERS_AREA_OFFSET
+#define TFM_OTP_NV_COUNTERS_SECTOR_SIZE FLASH_OTP_NV_COUNTERS_SECTOR_SIZE
+#define TFM_OTP_NV_COUNTERS_BACKUP_AREA_ADDR (TFM_OTP_NV_COUNTERS_AREA_ADDR + \
+                                              TFM_OTP_NV_COUNTERS_AREA_SIZE)
+
+#endif /* __FLASH_LAYOUT_H__ */
diff --git a/platform/ext/target/rpi/rp2350/partition/region_defs.h b/platform/ext/target/rpi/rp2350/partition/region_defs.h
new file mode 100644
index 0000000..ec57475
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/partition/region_defs.h
@@ -0,0 +1,170 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __REGION_DEFS_H__
+#define __REGION_DEFS_H__
+
+#ifdef NO_U_MODIFIER
+#define _u(x) x
+#endif
+
+#include "flash_layout.h"
+#include "hardware/regs/addressmap.h" /* Coming from SDK */
+
+#define BL2_HEAP_SIZE           (0x0001000)
+#define BL2_MSP_STACK_SIZE      (0x0001800)
+
+#ifdef ENABLE_HEAP
+#define S_HEAP_SIZE             (0x0000200)
+#endif
+
+#define S_MSP_STACK_SIZE        (0x0000800)
+#define S_PSP_STACK_SIZE        (0x0000800)
+
+#define NS_HEAP_SIZE            (0x0001000)
+#define NS_STACK_SIZE           (0x0001000)
+
+#ifdef BL2
+#ifndef LINK_TO_SECONDARY_PARTITION
+#define S_IMAGE_PRIMARY_PARTITION_OFFSET   (FLASH_AREA_0_OFFSET)
+#define S_IMAGE_SECONDARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET)
+#else
+#define S_IMAGE_PRIMARY_PARTITION_OFFSET   (FLASH_AREA_2_OFFSET)
+#define S_IMAGE_SECONDARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET)
+#endif /* !LINK_TO_SECONDARY_PARTITION */
+#else
+#define S_IMAGE_PRIMARY_PARTITION_OFFSET (0x0)
+#endif /* BL2 */
+
+#ifndef LINK_TO_SECONDARY_PARTITION
+#define NS_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET \
+                                           + FLASH_S_PARTITION_SIZE)
+#else
+#define NS_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET \
+                                           + FLASH_S_PARTITION_SIZE)
+#endif /* !LINK_TO_SECONDARY_PARTITION */
+
+/* IMAGE_CODE_SIZE is the space available for the software binary image.
+ * It is less than the FLASH_S_PARTITION_SIZE + FLASH_NS_PARTITION_SIZE
+ * because we reserve space for the image header and trailer introduced
+ * by the bootloader.
+ */
+#if (!defined(MCUBOOT_IMAGE_NUMBER) || (MCUBOOT_IMAGE_NUMBER == 1)) && \
+    (NS_IMAGE_PRIMARY_PARTITION_OFFSET > S_IMAGE_PRIMARY_PARTITION_OFFSET)
+/* If secure image and nonsecure image are concatenated, and nonsecure image
+ * locates at the higher memory range, then the secure image does not need
+ * the trailer area.
+ */
+#define IMAGE_S_CODE_SIZE \
+            (FLASH_S_PARTITION_SIZE - BL2_HEADER_SIZE)
+#else
+#define IMAGE_S_CODE_SIZE \
+            (FLASH_S_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
+#endif
+
+#define IMAGE_NS_CODE_SIZE \
+            (FLASH_NS_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
+
+/* Secure regions */
+#define S_IMAGE_PRIMARY_AREA_OFFSET \
+             (S_IMAGE_PRIMARY_PARTITION_OFFSET + BL2_HEADER_SIZE)
+/* Secure Code stored in Flash */
+#define S_CODE_START    ((XIP_BASE) + (S_IMAGE_PRIMARY_AREA_OFFSET))
+#define S_CODE_SIZE     (IMAGE_S_CODE_SIZE)
+#define S_CODE_LIMIT    (S_CODE_START + S_CODE_SIZE - 1)
+
+#define S_DATA_OVERALL_SIZE         (0x30000) /* 192 KB */
+
+/* Secure Data stored in SRAM0-3 */
+#define S_DATA_START    (SRAM0_BASE)
+#define S_DATA_SIZE     (S_DATA_OVERALL_SIZE)
+#define S_DATA_LIMIT    (S_DATA_START + S_DATA_SIZE - 1)
+
+/* Size of vector table: 52 + 16 entry -> 0x110 bytes */
+/* Not defined, reason: TFM_VECTORS contain default handler implementations as
+   well, which increases the standard size, resulting a failed check in linker
+   script */
+//#define S_CODE_VECTOR_TABLE_SIZE    (0x110)
+/* This is used instead of the above */
+#define NS_VECTOR_ALLOCATED_SIZE 0x124
+
+/* Non-secure regions */
+#define NS_IMAGE_PRIMARY_AREA_OFFSET \
+                        (NS_IMAGE_PRIMARY_PARTITION_OFFSET + BL2_HEADER_SIZE)
+/* Non-Secure Code stored in Code SRAM memory */
+#define NS_CODE_START   ((XIP_BASE) + (NS_IMAGE_PRIMARY_AREA_OFFSET))
+#define NS_CODE_SIZE    (IMAGE_NS_CODE_SIZE)
+#define NS_CODE_LIMIT   (NS_CODE_START + NS_CODE_SIZE - 1)
+
+/* Entry point of Core1 */
+#define NS_CODE_CORE1_START (NS_CODE_START + NS_VECTOR_ALLOCATED_SIZE)
+
+#define NS_DATA_OVERALL_SIZE         (0x40000)
+
+/* Non-Secure Data stored in ISRAM0+ISRAM1 */
+#define NS_DATA_START   (SRAM4_BASE)
+#define NS_DATA_SIZE    (NS_DATA_OVERALL_SIZE)
+#define NS_DATA_LIMIT   (NS_DATA_START + NS_DATA_SIZE - 1)
+
+/* NS partition information is used for SAU configuration */
+#define NS_PARTITION_START \
+            ((XIP_BASE) + (NS_IMAGE_PRIMARY_PARTITION_OFFSET))
+#define NS_PARTITION_SIZE (FLASH_NS_PARTITION_SIZE)
+
+/* Secondary partition for new images in case of firmware upgrade */
+#define SECONDARY_PARTITION_START \
+            ((XIP_BASE) + (S_IMAGE_SECONDARY_PARTITION_OFFSET))
+#define SECONDARY_PARTITION_SIZE (FLASH_S_PARTITION_SIZE + \
+                                  FLASH_NS_PARTITION_SIZE)
+
+#ifdef BL2
+/* Bootloader regions */
+#define BL2_CODE_START    (XIP_BASE)
+#define BL2_CODE_SIZE     (FLASH_AREA_BL2_SIZE)
+#define BL2_CODE_LIMIT    (BL2_CODE_START + BL2_CODE_SIZE - 1)
+
+/* Bootloader uses same memory as for secure image */
+#define BL2_DATA_START    (S_DATA_START)
+#define BL2_DATA_SIZE     (S_DATA_SIZE)
+#define BL2_DATA_LIMIT    (BL2_DATA_START + BL2_DATA_SIZE - 1)
+#endif /* BL2 */
+
+/* Shared data area between bootloader and runtime firmware.
+ * Shared data area is allocated at the beginning of the RAM, it is overlapping
+ * with TF-M Secure code's MSP stack
+ */
+#define BOOT_TFM_SHARED_DATA_BASE S_DATA_START
+#define BOOT_TFM_SHARED_DATA_SIZE (0x400)
+#define BOOT_TFM_SHARED_DATA_LIMIT (BOOT_TFM_SHARED_DATA_BASE + \
+                                    BOOT_TFM_SHARED_DATA_SIZE - 1)
+
+#define PROVISIONING_BUNDLE_CODE_START (NS_DATA_START)
+#define PROVISIONING_BUNDLE_CODE_SIZE  (PROVISIONING_CODE_PADDED_SIZE)
+/* The max size of the values(keys, seeds) that are going to be provisioned
+ * into the OTP. */
+#define PROVISIONING_BUNDLE_VALUES_START (PROVISIONING_BUNDLE_CODE_START + PROVISIONING_BUNDLE_CODE_SIZE)
+#define PROVISIONING_BUNDLE_VALUES_SIZE (PROVISIONING_VALUES_PADDED_SIZE)
+#define PROVISIONING_BUNDLE_DATA_START (PROVISIONING_BUNDLE_VALUES_START + \
+                                        PROVISIONING_BUNDLE_VALUES_SIZE)
+#define PROVISIONING_BUNDLE_DATA_SIZE (PROVISIONING_DATA_PADDED_SIZE)
+
+#define PROVISIONING_BUNDLE_START (XIP_BASE + FLASH_OTP_NV_COUNTERS_AREA_OFFSET + FLASH_OTP_NV_COUNTERS_AREA_SIZE)
+#define PROVISIONING_BUNDLE_MAGIC (0x18)
+
+#if ((PROVISIONING_BUNDLE_START + PROVISIONING_BUNDLE_CODE_SIZE + PROVISIONING_BUNDLE_VALUES_SIZE + \
+     PROVISIONING_BUNDLE_DATA_SIZE + PROVISIONING_BUNDLE_MAGIC) > XIP_BASE + FLASH_TOTAL_SIZE)
+#error "Out of flash memory!"
+#endif
+
+/* Enable scratch regions for pico-rp2350 */
+#define __ENABLE_SCRATCH__
+
+#define SCRATCH_X_START (BL2_DATA_START + BL2_DATA_SIZE)
+#define SCRATCH_X_SIZE  0x1000
+#define SCRATCH_Y_START (SCRATCH_X_START + SCRATCH_X_SIZE)
+#define SCRATCH_Y_SIZE  0x1000
+
+#endif /* __REGION_DEFS_H__ */
diff --git a/platform/ext/target/rpi/rp2350/pico-sdk.patch b/platform/ext/target/rpi/rp2350/pico-sdk.patch
new file mode 100644
index 0000000..0ff2fbf
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/pico-sdk.patch
@@ -0,0 +1,39 @@
+diff --git a/src/common/pico_sync/sem.c b/src/common/pico_sync/sem.c
+index 9044817..8fc4458 100644
+--- a/src/common/pico_sync/sem.c
++++ b/src/common/pico_sync/sem.c
+@@ -15,7 +15,7 @@ void sem_init(semaphore_t *sem, int16_t initial_permits, int16_t max_permits) {
+ }
+ 
+ int __time_critical_func(sem_available)(semaphore_t *sem) {
+-#ifdef __GNUC__
++#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+     return *(volatile typeof(sem->permits) *) &sem->permits;
+ #else
+     static_assert(sizeof(sem->permits) == 2, "");
+diff --git a/src/rp2_common/pico_bootrom/CMakeLists.txt b/src/rp2_common/pico_bootrom/CMakeLists.txt
+index 0648098..93a52ea 100644
+--- a/src/rp2_common/pico_bootrom/CMakeLists.txt
++++ b/src/rp2_common/pico_bootrom/CMakeLists.txt
+@@ -8,5 +8,5 @@ target_sources(pico_bootrom INTERFACE
+         ${CMAKE_CURRENT_LIST_DIR}/bootrom_lock.c
+         )
+ 
+-target_link_libraries(pico_bootrom_headers INTERFACE boot_picoboot_headers)
++target_link_libraries(pico_bootrom_headers INTERFACE boot_picoboot_headers boot_picobin_headers)
+ pico_mirrored_target_link_libraries(pico_bootrom INTERFACE pico_base hardware_boot_lock)
+diff --git a/src/rp2_common/pico_multicore/multicore.c b/src/rp2_common/pico_multicore/multicore.c
+index 58c2ee2..6ec689f 100644
+--- a/src/rp2_common/pico_multicore/multicore.c
++++ b/src/rp2_common/pico_multicore/multicore.c
+@@ -100,8 +100,8 @@ int core1_wrapper(int (*entry)(void), void *stack_base) {
+ void multicore_reset_core1(void) {
+     // Use atomic aliases just in case core 1 is also manipulating some PSM state
+     io_rw_32 *power_off = (io_rw_32 *) (PSM_BASE + PSM_FRCE_OFF_OFFSET);
+-    io_rw_32 *power_off_set = hw_set_alias(power_off);
+-    io_rw_32 *power_off_clr = hw_clear_alias(power_off);
++    io_rw_32 *power_off_set = hw_set_alias_untyped(power_off);
++    io_rw_32 *power_off_clr = hw_clear_alias_untyped(power_off);
+ 
+     // Hard-reset core 1.
+     // Reading back confirms the core 1 reset is in the correct state, but also
diff --git a/platform/ext/target/rpi/rp2350/pico_sdk_import.cmake b/platform/ext/target/rpi/rp2350/pico_sdk_import.cmake
new file mode 100644
index 0000000..9644ea2
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/pico_sdk_import.cmake
@@ -0,0 +1,88 @@
+# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
+
+# This can be dropped into an external project to help locate this SDK
+# It should be include()ed prior to project()
+
+if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
+    set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
+    message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
+    set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
+    message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
+    set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
+    message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
+    set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
+    message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
+endif ()
+
+if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
+  set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
+  message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
+endif()
+
+set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
+set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
+set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
+set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
+find_package(Git)
+set(PICO_SDK_PATCH_COMMAND ${GIT_EXECUTABLE} reset --hard --quiet && ${GIT_EXECUTABLE} apply "${CMAKE_CURRENT_LIST_DIR}/pico-sdk.patch")
+
+if (NOT PICO_SDK_PATH)
+    if (PICO_SDK_FETCH_FROM_GIT)
+        include(FetchContent)
+        set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
+        if (PICO_SDK_FETCH_FROM_GIT_PATH)
+            get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
+        endif ()
+        # GIT_SUBMODULES_RECURSE was added in 3.17
+        if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
+            FetchContent_Declare(
+                    pico_sdk
+                    GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
+                    GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
+                    GIT_SUBMODULES_RECURSE FALSE
+                    PATCH_COMMAND ${PICO_SDK_PATCH_COMMAND}
+            )
+        else ()
+            FetchContent_Declare(
+                    pico_sdk
+                    GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
+                    GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
+                    PATCH_COMMAND ${PICO_SDK_PATCH_COMMAND}
+            )
+        endif ()
+
+        if (NOT pico_sdk)
+            message("Downloading Raspberry Pi Pico SDK")
+            FetchContent_Populate(pico_sdk)
+            set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
+        endif ()
+        set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
+    else ()
+        message(FATAL_ERROR
+                "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
+                )
+    endif ()
+endif ()
+
+get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
+if (NOT EXISTS ${PICO_SDK_PATH})
+    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
+endif ()
+
+set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
+if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
+    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
+endif ()
+
+set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
+
+include(${PICO_SDK_INIT_CMAKE_FILE})
diff --git a/platform/ext/target/rpi/rp2350/plat_test.c b/platform/ext/target/rpi/rp2350/plat_test.c
new file mode 100644
index 0000000..fef65b8
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/plat_test.c
@@ -0,0 +1,63 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+
+#include "tfm_plat_test.h"
+#include "hardware/timer.h"
+#include "hardware/irq.h"
+
+#define TIMER0_IRQ0_NUM 0
+#define TIMER_MS 1000
+#define TIMER_DELAY_US (500 * TIMER_MS)
+
+extern void TFM_TIMER0_IRQ_Handler(void);
+
+#ifdef TFM_PARTITION_SLIH_TEST
+TFM_LINK_SET_RO_IN_PARTITION_SECTION("TFM_SP_SLIH_TEST", "APP-ROT")
+#elif defined(TFM_PARTITION_FLIH_TEST)
+TFM_LINK_SET_RO_IN_PARTITION_SECTION("TFM_SP_FLIH_TEST", "APP-ROT")
+#endif
+void tfm_plat_test_secure_timer_set_alarm_in_us(uint32_t delay_us)
+{
+    /* Load timer */
+    uint64_t target = timer0_hw->timerawl + delay_us;
+
+    /* Write the lower 32 bits of the target time to the alarm which will
+       arm it */
+    timer0_hw->alarm[TIMER0_IRQ0_NUM] = (uint32_t) target;
+}
+
+void tfm_plat_test_secure_timer_irq_handler(void)
+{
+    TFM_TIMER0_IRQ_Handler();
+    tfm_plat_test_secure_timer_set_alarm_in_us(TIMER_DELAY_US);
+}
+
+void tfm_plat_test_secure_timer_start(void)
+{
+    /* Enable Timer0_0 interrupt */
+    hw_set_bits(&timer0_hw->inte, 1u << TIMER0_IRQ0_NUM);
+    tfm_plat_test_secure_timer_set_alarm_in_us(TIMER_DELAY_US);
+}
+
+void tfm_plat_test_secure_timer_clear_intr(void)
+{
+    hw_clear_bits(&timer0_hw->intr, 1u << TIMER0_IRQ0_NUM);
+}
+
+void tfm_plat_test_secure_timer_stop(void)
+{
+    /* Disable Timer0_0 interrupt */
+    hw_clear_bits(&timer0_hw->inte, 1u << TIMER0_IRQ0_NUM);
+}
+
+void tfm_plat_test_non_secure_timer_start(void)
+{
+}
+
+void tfm_plat_test_non_secure_timer_stop(void)
+{
+}
diff --git a/platform/ext/target/rpi/rp2350/platform_builtin_key_loader_ids.h b/platform/ext/target/rpi/rp2350/platform_builtin_key_loader_ids.h
new file mode 100644
index 0000000..b76d67c
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/platform_builtin_key_loader_ids.h
@@ -0,0 +1,26 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __PLATFORM_BUILTIN_KEY_LOADER_IDS_H__
+#define __PLATFORM_BUILTIN_KEY_LOADER_IDS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TFM_BUILTIN_MAX_KEY_LEN 96
+
+enum psa_drv_slot_number_t {
+    TFM_BUILTIN_KEY_SLOT_HUK = 0,
+    TFM_BUILTIN_KEY_SLOT_IAK,
+    TFM_BUILTIN_KEY_SLOT_MAX,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PLATFORM_BUILTIN_KEY_LOADER_IDS_H__ */
diff --git a/platform/ext/target/rpi/rp2350/platform_multicore.h b/platform/ext/target/rpi/rp2350/platform_multicore.h
new file mode 100644
index 0000000..3054886
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/platform_multicore.h
@@ -0,0 +1,48 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __PLATFORM_MULTICORE_H__
+#define __PLATFORM_MULTICORE_H__
+
+#include <stdint.h>
+
+#include "hardware/structs/sio.h"
+
+#define CORE1_S_READY           0x10
+#define CORE1_NS_READY          0x20
+#define CORE0_NS_READY          0x30
+
+#define NS_MAILBOX_INIT         0x100
+#define S_MAILBOX_READY         0x110
+
+#define NOTIFY_FROM_CORE0       0x200
+#define NOTIFY_FROM_CORE1       0x300
+
+#define HALT_DOORBELL_MASK      (0x1UL << 0)
+#define FLASH_DOORBELL_MASK     (0x1UL << 1)
+
+#define UART_SPINLOCK_NUM       0
+#define FLASH_SPINLOCK_NUM      1
+#define MAILBOX_SPINLOCK_NUM    2
+
+#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
+#define UART_SPINLOCK           (&sio_ns_hw->spinlock[UART_SPINLOCK_NUM])
+#define FLASH_SPINLOCK          (&sio_hw->spinlock[FLASH_SPINLOCK_NUM])
+#define MAILBOX_SPINLOCK        (&sio_ns_hw->spinlock[MAILBOX_SPINLOCK_NUM])
+#else
+#define UART_SPINLOCK           (&sio_hw->spinlock[UART_SPINLOCK_NUM])
+#define MAILBOX_SPINLOCK        (&sio_hw->spinlock[MAILBOX_SPINLOCK_NUM])
+#endif
+
+
+bool multicore_ns_fifo_rvalid(void);
+bool multicore_ns_fifo_wready(void);
+void multicore_ns_fifo_push_blocking_inline(uint32_t data);
+uint32_t multicore_ns_fifo_pop_blocking_inline(void);
+extern volatile uint32_t CORE1_RUNNING;
+
+
+#endif  /* __PLATFORM_MULTICORE_H__ */
diff --git a/platform/ext/target/rpi/rp2350/platform_nv_counters_ids.h b/platform/ext/target/rpi/rp2350/platform_nv_counters_ids.h
new file mode 100644
index 0000000..1112e2e
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/platform_nv_counters_ids.h
@@ -0,0 +1,33 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __PLATFORM_NV_COUNTERS_IDS_H__
+#define __PLATFORM_NV_COUNTERS_IDS_H__
+
+#include <stdint.h>
+
+enum tfm_nv_counter_t {
+    PLAT_NV_COUNTER_PS_0 = 0,  /* Used by PS service */
+    PLAT_NV_COUNTER_PS_1,      /* Used by PS service */
+    PLAT_NV_COUNTER_PS_2,      /* Used by PS service */
+
+    /* BL2 NV counters must be contiguous */
+    PLAT_NV_COUNTER_BL2_0,     /* Used by bootloader */
+    PLAT_NV_COUNTER_BL2_1,     /* Used by bootloader */
+    PLAT_NV_COUNTER_BL2_2,     /* Used by bootloader */
+    PLAT_NV_COUNTER_BL2_3,     /* Used by bootloader */
+
+    /* NS counters must be contiguous */
+    PLAT_NV_COUNTER_NS_0,      /* Used by NS */
+    PLAT_NV_COUNTER_NS_1,      /* Used by NS */
+    PLAT_NV_COUNTER_NS_2,      /* Used by NS */
+
+    PLAT_NV_COUNTER_MAX,
+    PLAT_NV_COUNTER_BOUNDARY = UINT32_MAX  /* Fix  tfm_nv_counter_t size
+                                              to 4 bytes */
+};
+
+#endif /* __PLATFORM_NV_COUNTERS_IDS_H__ */
diff --git a/platform/ext/target/rpi/rp2350/platform_otp_ids.h b/platform/ext/target/rpi/rp2350/platform_otp_ids.h
new file mode 100644
index 0000000..cad3f07
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/platform_otp_ids.h
@@ -0,0 +1,62 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __PLATFORM_OTP_IDS_H__
+#define __PLATFORM_OTP_IDS_H__
+
+#include <stdint.h>
+
+enum tfm_otp_element_id_t {
+    PLAT_OTP_ID_HUK = 0,
+    PLAT_OTP_ID_GUK,
+    PLAT_OTP_ID_IAK,
+    PLAT_OTP_ID_IAK_LEN,
+    PLAT_OTP_ID_IAK_TYPE,
+    PLAT_OTP_ID_IAK_ID,
+
+    PLAT_OTP_ID_BOOT_SEED,
+    PLAT_OTP_ID_LCS,
+    PLAT_OTP_ID_IMPLEMENTATION_ID,
+    PLAT_OTP_ID_CERT_REF,
+    PLAT_OTP_ID_VERIFICATION_SERVICE_URL,
+    PLAT_OTP_ID_PROFILE_DEFINITION,
+
+    /* BL2 ROTPK must be contiguous */
+    PLAT_OTP_ID_BL2_ROTPK_0,
+    PLAT_OTP_ID_BL2_ROTPK_1,
+    PLAT_OTP_ID_BL2_ROTPK_2,
+    PLAT_OTP_ID_BL2_ROTPK_3,
+
+    /* BL2 NV counters must be contiguous */
+    PLAT_OTP_ID_NV_COUNTER_BL2_0,
+    PLAT_OTP_ID_NV_COUNTER_BL2_1,
+    PLAT_OTP_ID_NV_COUNTER_BL2_2,
+    PLAT_OTP_ID_NV_COUNTER_BL2_3,
+
+    PLAT_OTP_ID_NV_COUNTER_NS_0,
+    PLAT_OTP_ID_NV_COUNTER_NS_1,
+    PLAT_OTP_ID_NV_COUNTER_NS_2,
+
+    PLAT_OTP_ID_KEY_BL2_ENCRYPTION,
+    PLAT_OTP_ID_BL1_2_IMAGE,
+    PLAT_OTP_ID_BL1_2_IMAGE_HASH,
+    PLAT_OTP_ID_BL2_IMAGE_HASH,
+    PLAT_OTP_ID_BL1_ROTPK_0,
+
+    PLAT_OTP_ID_NV_COUNTER_BL1_0,
+
+    PLAT_OTP_ID_ENTROPY_SEED,
+
+    PLAT_OTP_ID_SECURE_DEBUG_PK,
+
+    PLAT_OTP_ID_NV_COUNTER_PS_0,
+    PLAT_OTP_ID_NV_COUNTER_PS_1,
+    PLAT_OTP_ID_NV_COUNTER_PS_2,
+
+    PLAT_OTP_ID_MAX = UINT32_MAX,
+};
+
+#endif /* __PLATFORM_OTP_IDS_H__ */
diff --git a/platform/ext/target/rpi/rp2350/rp2350_otp.c b/platform/ext/target/rpi/rp2350/rp2350_otp.c
new file mode 100644
index 0000000..c2f1499
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/rp2350_otp.c
@@ -0,0 +1,257 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_plat_otp.h"
+#include "pico/bootrom.h"
+#include "hardware/regs/otp_data.h"
+#include <string.h>
+
+#define OTP_BUFFER_MASK 0x0000FFFF
+#define OTP_IS_WRITE_MASK 0x00010000
+#define OTP_IS_ECC_MASK 0x00020000
+#define OTP_ROW_PER_PAGE 0x40
+
+struct rp2350_otp_element_t {
+    uint16_t row_offset; /* OTP row offset, used in otp_access() bootrom api */
+    uint8_t byte_len; /* Length of the element in bytes, should be aligned(2) or
+                    aligned(4) depending usage mode */
+};
+
+/* RP2350 OTP is accessable through the bootrom api: otp_access. This OTP is
+   organized into pages and rows, it has 64 pages, each 64 rows in size, 4096
+   rows altogether. Each row has 24 bits (16 bit data, 8bit ECC). Because of its
+   structure accesses have to be aligned to 2 bytes. The default OTP elements
+   need to be placed here. This sturct serves as a map between rows and
+   tfm_otp_element_id_t ids.
+   The first 3 pages are occupied.
+*/
+static const struct rp2350_otp_element_t otp_map[] = {
+    [PLAT_OTP_ID_HUK] =                      {.row_offset = 0xC0 + 0x00 , .byte_len = 32 },
+    [PLAT_OTP_ID_GUK] =                      {.row_offset = 0xC0 + 0x10 , .byte_len = 32 },
+    [PLAT_OTP_ID_IAK] =                      {.row_offset = 0xC0 + 0x20 , .byte_len = 32 },
+    [PLAT_OTP_ID_IAK_LEN] =                  {.row_offset = 0xC0 + 0x30 , .byte_len = 4  },
+    [PLAT_OTP_ID_IAK_TYPE] =                 {.row_offset = 0xC0 + 0x32 , .byte_len = 4  },
+    [PLAT_OTP_ID_IAK_ID] =                   {.row_offset = 0xC0 + 0x34 , .byte_len = 32 },
+    [PLAT_OTP_ID_BOOT_SEED] =                {.row_offset = 0xC0 + 0x44 , .byte_len = 32 },
+    [PLAT_OTP_ID_LCS] =                      {.row_offset = 0xC0 + 0x54 , .byte_len = 4  },
+    [PLAT_OTP_ID_IMPLEMENTATION_ID] =        {.row_offset = 0xC0 + 0x56 , .byte_len = 32 },
+    [PLAT_OTP_ID_CERT_REF] =                 {.row_offset = 0xC0 + 0x66 , .byte_len = 32 },
+    [PLAT_OTP_ID_VERIFICATION_SERVICE_URL] = {.row_offset = 0xC0 + 0x76 , .byte_len = 32 },
+    [PLAT_OTP_ID_PROFILE_DEFINITION] =       {.row_offset = 0xC0 + 0x86 , .byte_len = 32 },
+    [PLAT_OTP_ID_BL2_ROTPK_0] =              {.row_offset = 0xC0 + 0x96 , .byte_len = 100},
+    [PLAT_OTP_ID_BL2_ROTPK_1] =              {.row_offset = 0xC0 + 0xC8 , .byte_len = 100},
+    [PLAT_OTP_ID_BL2_ROTPK_2] =              {.row_offset = 0xC0 + 0xFA , .byte_len = 100},
+    [PLAT_OTP_ID_BL2_ROTPK_3] =              {.row_offset = 0xC0 + 0x12C, .byte_len = 100},
+    [PLAT_OTP_ID_NV_COUNTER_BL2_0] =         {.row_offset = 0xC0 + 0x15E, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_BL2_1] =         {.row_offset = 0xC0 + 0x17E, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_BL2_2] =         {.row_offset = 0xC0 + 0x19E, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_BL2_3] =         {.row_offset = 0xC0 + 0x1BE, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_NS_0] =          {.row_offset = 0xC0 + 0x1DE, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_NS_1] =          {.row_offset = 0xC0 + 0x1FE, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_NS_2] =          {.row_offset = 0xC0 + 0x21E, .byte_len = 64 },
+    [PLAT_OTP_ID_KEY_BL2_ENCRYPTION] =       {.row_offset = 0xC0 + 0x23E, .byte_len = 0  },
+    [PLAT_OTP_ID_BL1_2_IMAGE] =              {.row_offset = 0xC0 + 0x23E, .byte_len = 0  },
+    [PLAT_OTP_ID_BL1_2_IMAGE_HASH] =         {.row_offset = 0xC0 + 0x23E, .byte_len = 0  },
+    [PLAT_OTP_ID_BL2_IMAGE_HASH] =           {.row_offset = 0xC0 + 0x23E, .byte_len = 0  },
+    [PLAT_OTP_ID_BL1_ROTPK_0] =              {.row_offset = 0xC0 + 0x23E, .byte_len = 0  },
+    [PLAT_OTP_ID_NV_COUNTER_BL1_0] =         {.row_offset = 0xC0 + 0x23E, .byte_len = 0  },
+    [PLAT_OTP_ID_ENTROPY_SEED] =             {.row_offset = 0xC0 + 0x23E, .byte_len = 64 },
+    [PLAT_OTP_ID_SECURE_DEBUG_PK] =          {.row_offset = 0xC0 + 0x25E, .byte_len = 32 },
+    [PLAT_OTP_ID_NV_COUNTER_PS_0] =          {.row_offset = 0xC0 + 0x26E, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_PS_1] =          {.row_offset = 0xC0 + 0x28E, .byte_len = 64 },
+    [PLAT_OTP_ID_NV_COUNTER_PS_2] =          {.row_offset = 0xC0 + 0x2AE, .byte_len = 64 },
+};
+
+enum tfm_plat_err_t tfm_plat_otp_init(void)
+{
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_otp_read(enum tfm_otp_element_id_t id,
+                                      size_t out_len, uint8_t *out)
+{
+    otp_cmd_t row_and_flags;
+    otp_cmd_t odd_byte_row_and_flags;
+    int rc = 0;
+    size_t out_len_checked;
+    uint8_t odd_byte_buff[2] = {0};
+    uint8_t *odd_byte_p;
+
+
+    if ((out_len == 0) || (otp_map[id].byte_len == 0)) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    if (id >= PLAT_OTP_ID_MAX) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Output buffer can be bigger than the OTP element */
+    out_len_checked = (out_len < otp_map[id].byte_len) ? out_len : otp_map[id].byte_len;
+
+    /* Assemble command */
+    row_and_flags.flags = (OTP_BUFFER_MASK & otp_map[id].row_offset);
+    /* For LCS ECC is not used so it can be updated */
+    if (id != PLAT_OTP_ID_LCS) {
+        row_and_flags.flags |= OTP_IS_ECC_MASK;
+    }
+
+    /* Read OTP through API */
+    /* Bootrom API requires 2 byte alignment with ECC mode ON, handle odd byte separately */
+    if (out_len_checked % 2) {
+        /* Update len to be even */
+        out_len_checked -= 1;
+        /* Assemble the command for the odd byte, row number is incremented by (len in byte)/2 */
+        odd_byte_row_and_flags.flags = row_and_flags.flags + (out_len_checked / 2);
+        /* Set pointer to the last byte of the output (not the buffer) */
+        odd_byte_p = out + out_len_checked;
+
+        rc = rom_func_otp_access(&odd_byte_buff[0], 2, odd_byte_row_and_flags);
+        if (rc) {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+        memcpy(odd_byte_p, &odd_byte_buff[0], 1);
+    }
+    if (out_len_checked) {
+        rc = rom_func_otp_access(out, out_len_checked, row_and_flags);
+        if (rc) {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+
+}
+
+enum tfm_plat_err_t tfm_plat_otp_write(enum tfm_otp_element_id_t id,
+                                       size_t in_len, const uint8_t *in)
+{
+    otp_cmd_t row_and_flags;
+    otp_cmd_t odd_byte_row_and_flags;
+    int rc = 0;
+    size_t in_len_checked;
+    uint8_t odd_byte_buff[2] = {0};
+    uint8_t *odd_byte_p;
+
+    if ((in_len == 0) || (otp_map[id].byte_len == 0)) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    if (id >= PLAT_OTP_ID_MAX) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    in_len_checked = (in_len < otp_map[id].byte_len) ? in_len : otp_map[id].byte_len;
+
+    /* Assemble command */
+    row_and_flags.flags =  OTP_IS_WRITE_MASK |
+                    (OTP_BUFFER_MASK & otp_map[id].row_offset);
+    /* For LCS ECC is not used so it can be updated */
+    if (id != PLAT_OTP_ID_LCS) {
+        row_and_flags.flags |= OTP_IS_ECC_MASK;
+    }
+
+    /* Write OTP through API */
+    /* Bootrom API requires 2 byte alignment with ECC mode ON, handle odd byte separately */
+    if (in_len_checked % 2) {
+        /* Update len to be even */
+        in_len_checked -= 1;
+        /* Assemble the command for the odd byte, row number is incremented by (len in byte)/2 */
+        odd_byte_row_and_flags.flags = row_and_flags.flags + (in_len_checked / 2);
+        /* Set pointer to the last byte of the input (not the buffer) */
+        odd_byte_p = in + in_len_checked;
+        memcpy(&odd_byte_buff[0], odd_byte_p, 1);
+
+        rc = rom_func_otp_access(&odd_byte_buff[0], 2, odd_byte_row_and_flags);
+        if (rc) {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    if (in_len_checked) {
+        rc = rom_func_otp_access(in, in_len_checked, row_and_flags);
+        if (rc) {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_otp_get_size(enum tfm_otp_element_id_t id,
+                                          size_t *size)
+{
+    if (id >= PLAT_OTP_ID_MAX) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+    *size = otp_map[id].byte_len;
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_otp_secure_provisioning_start(void)
+{
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
+enum tfm_plat_err_t tfm_plat_otp_secure_provisioning_finish(void)
+{
+
+    uint32_t row_count = 0;
+    uint8_t first_page_to_lock;
+    uint8_t last_page_to_lock;
+    uint8_t num_pages_to_lock;
+    otp_cmd_t row_and_flags;
+    uint8_t msg_buff[4] = {0};
+    uint32_t lock_config;
+    int rc = 0;
+
+    /* Count the number of allocated OTP rows, assuming continious usage */
+    for (int i = 0; i <= PLAT_OTP_ID_SECURE_DEBUG_PK; i++) {
+        row_count += otp_map[i].byte_len;
+    }
+
+    /* Get the pages to be locked */
+    first_page_to_lock = otp_map[0].row_offset / OTP_ROW_PER_PAGE;
+
+    last_page_to_lock = (otp_map[PLAT_OTP_ID_SECURE_DEBUG_PK].row_offset +
+                         (otp_map[PLAT_OTP_ID_SECURE_DEBUG_PK].byte_len / 2)) /
+                        0x40;
+    num_pages_to_lock = last_page_to_lock - first_page_to_lock + 1;
+
+    /* First and last 3 pages are already in use */
+    if ((first_page_to_lock < 3) || (last_page_to_lock > 60)) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    /* Assmble message */
+    /* Lock information encoded to the first 8 bits of lock register 1 */
+    lock_config = (OTP_DATA_PAGE0_LOCK1_LOCK_NS_BITS &
+                   (OTP_DATA_PAGE0_LOCK1_LOCK_NS_VALUE_INACCESSIBLE <<
+                    OTP_DATA_PAGE0_LOCK1_LOCK_NS_LSB)) |
+                  (OTP_DATA_PAGE0_LOCK1_LOCK_BL_BITS &
+                   (OTP_DATA_PAGE0_LOCK1_LOCK_BL_VALUE_INACCESSIBLE <<
+                    OTP_DATA_PAGE0_LOCK1_LOCK_BL_LSB));
+    /* Triple majority vote */
+    msg_buff[0] = lock_config;
+    msg_buff[1] = lock_config;
+    msg_buff[2] = lock_config;
+
+    /* Lock pages, NS and BL code should not be able to access them */
+    for (int i = 0; i < num_pages_to_lock; i++) {
+        /* Assemble command */
+        row_and_flags.flags = OTP_IS_WRITE_MASK |
+                              (OTP_BUFFER_MASK & (OTP_DATA_PAGE0_LOCK1_ROW +
+                               ((i + first_page_to_lock) * 2)));
+
+        /* Write lock register PAGExx_LOCK1 */
+        rc = rom_func_otp_access(&msg_buff[0], 4, row_and_flags);
+        if (rc) {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
diff --git a/platform/ext/target/rpi/rp2350/rpi_trng.c b/platform/ext/target/rpi/rp2350/rpi_trng.c
new file mode 100644
index 0000000..dad35cd
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/rpi_trng.c
@@ -0,0 +1,38 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "psa/crypto.h"
+#include "pico/rand.h"
+#include <string.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+psa_status_t mbedtls_psa_external_get_random(mbedtls_psa_external_random_context_t *context,
+                                             uint8_t *output,
+                                             size_t output_size,
+                                             size_t *output_length)
+{
+    size_t i = 0;
+    size_t copy_size = 0;
+    size_t remaining_size = 0;
+
+    uint64_t tmp_trn;
+
+    (void) context;
+
+    while (i < output_size) {
+        remaining_size = output_size - i;
+        copy_size = (remaining_size > 8) ? 8 : remaining_size;
+
+        tmp_trn = get_rand_64();
+        memcpy(output + i, (uint8_t *)(&tmp_trn), copy_size);
+        i += copy_size;
+    }
+
+    *output_length = output_size;
+
+    return PSA_SUCCESS;
+}
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
diff --git a/platform/ext/target/rpi/rp2350/services/src/tfm_platform_system.c b/platform/ext/target/rpi/rp2350/services/src/tfm_platform_system.c
new file mode 100644
index 0000000..12c1835
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/services/src/tfm_platform_system.c
@@ -0,0 +1,28 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_platform_system.h"
+#include "tfm_hal_device_header.h"
+#include "tfm_hal_platform.h"
+
+void tfm_platform_hal_system_reset(void)
+{
+    __disable_irq();
+    tfm_hal_system_reset();
+}
+
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                               psa_invec  *in_vec,
+                                               psa_outvec *out_vec)
+{
+    (void)request;
+    (void)in_vec;
+    (void)out_vec;
+
+    /* Not needed for this platform */
+    return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+}
+
diff --git a/platform/ext/target/rpi/rp2350/static_assert_override.h b/platform/ext/target/rpi/rp2350/static_assert_override.h
new file mode 100644
index 0000000..300cc43
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/static_assert_override.h
@@ -0,0 +1,8 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#define static_assert(cond, message)
+#define asm __asm
diff --git a/platform/ext/target/rpi/rp2350/target_cfg.c b/platform/ext/target/rpi/rp2350/target_cfg.c
new file mode 100644
index 0000000..a610493
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/target_cfg.c
@@ -0,0 +1,320 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_hal_device_header.h"
+#include "region_defs.h"
+#include "target_cfg.h"
+#include "tfm_plat_defs.h"
+#include "tfm_peripherals_def.h"
+#include "hardware/uart.h"
+#include "region.h"
+#include "hardware/regs/addressmap.h"
+#include "hardware/structs/accessctrl.h"
+#include "hardware/structs/dma.h"
+
+#define REG_RW(addr) (*(volatile uint32_t *)(addr))
+
+#define ACCESSCTRL_DBG (1U << 7)
+#define ACCESSCTRL_DMA (1U << 6)
+#define ACCESSCTRL_CORE1 (1U << 5)
+#define ACCESSCTRL_CORE0 (1U << 4)
+#define ACCESSCTRL_SP (1U << 3)
+#define ACCESSCTRL_SU (1U << 2)
+#define ACCESSCTRL_NSP (1U << 1)
+#define ACCESSCTRL_NSU (1U << 0)
+
+#define ACCESSCTRL_NS_PRIV (ACCESSCTRL_DBG | ACCESSCTRL_DMA |    \
+                              ACCESSCTRL_CORE1 | ACCESSCTRL_CORE0 |\
+                              ACCESSCTRL_SP | ACCESSCTRL_SU |      \
+                              ACCESSCTRL_NSP)
+#define ACCESSCTRL_S_UNPRIV_C0 (ACCESSCTRL_DBG | ACCESSCTRL_CORE0 |\
+                                ACCESSCTRL_SP | ACCESSCTRL_SU)
+/* Only grant access to Core0 when Multi-core topology is not in use */
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+#define ACCESSCTRL_S_UNPRIV_C0_C1 (ACCESSCTRL_DBG | ACCESSCTRL_CORE0 |\
+                                   ACCESSCTRL_CORE1 | ACCESSCTRL_SP |\
+                                   ACCESSCTRL_SU)
+#else
+#define ACCESSCTRL_S_UNPRIV_C0_C1 ACCESSCTRL_S_UNPRIV_C0
+#endif
+#define ACCESSCTRL_S_PRIV_C0 (ACCESSCTRL_DBG | ACCESSCTRL_CORE0 |\
+                              ACCESSCTRL_SP)
+
+
+#ifdef CONFIG_TFM_USE_TRUSTZONE
+REGION_DECLARE(Image$$, ER_VENEER, $$Base);
+REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
+#endif /* CONFIG_TFM_USE_TRUSTZONE */
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
+REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
+#ifdef CONFIG_TFM_PARTITION_META
+REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit);
+#endif /* CONFIG_TFM_PARTITION_META */
+
+#define FF_TEST_NVMEM_REGION_START            0x2005E000
+#define FF_TEST_NVMEM_REGION_END              0x2005E3FF
+#define FF_TEST_SERVER_PARTITION_MMIO_START   0x2005E400
+#define FF_TEST_SERVER_PARTITION_MMIO_END     0x2005E4FF
+#define FF_TEST_DRIVER_PARTITION_MMIO_START   0x2005E600
+#define FF_TEST_DRIVER_PARTITION_MMIO_END     0x2005E6FF
+
+extern const struct memory_region_limits memory_regions;
+
+struct platform_data_t tfm_peripheral_std_uart = {
+        .periph_start = UART0_BASE,
+        .periph_limit = UART0_BASE + 0x3FFF,
+        /* Based on platform_data_t definition TF-M expects PPC to control
+           security and privilege settings. There is no PPC on this platform.
+           Using periph_ppc_mask to store accessctrl register index. */
+        .periph_ppc_mask = AC_DO_NOT_CONFIGURE,
+};
+
+struct platform_data_t tfm_peripheral_timer0 = {
+        .periph_start = TIMER0_BASE,
+        .periph_limit = TIMER0_BASE + 0x3FFF,
+        /* Based on platform_data_t definition TF-M expects PPC to control
+           security and privilege settings. There is no PPC on this platform.
+           Using periph_ppc_mask to store accessctrl register index. */
+        .periph_ppc_mask = AC_TIMER0,
+};
+
+#ifdef PSA_API_TEST_IPC
+
+/* Below data structure are only used for PSA FF tests, and this pattern is
+ * definitely not to be followed for real life use cases, as it can break
+ * security.
+ */
+
+struct platform_data_t
+    tfm_peripheral_FF_TEST_UART_REGION = {
+        .periph_start = UART1_BASE,
+        .periph_limit = UART1_BASE + 0x3FFF,
+        .periph_ppc_mask = AC_UART1,
+};
+
+struct platform_data_t
+    tfm_peripheral_FF_TEST_WATCHDOG_REGION = {
+        .periph_start = WATCHDOG_BASE,
+        .periph_limit = WATCHDOG_BASE + 0x3FFF,
+        .periph_ppc_mask = AC_DO_NOT_CONFIGURE,
+};
+
+struct platform_data_t
+    tfm_peripheral_FF_TEST_NVMEM_REGION = {
+        .periph_start = FF_TEST_NVMEM_REGION_START,
+        .periph_limit = FF_TEST_NVMEM_REGION_END,
+        .periph_ppc_mask = AC_DO_NOT_CONFIGURE
+};
+
+struct platform_data_t
+    tfm_peripheral_FF_TEST_SERVER_PARTITION_MMIO = {
+        .periph_start = FF_TEST_SERVER_PARTITION_MMIO_START,
+        .periph_limit = FF_TEST_SERVER_PARTITION_MMIO_END,
+        .periph_ppc_mask = AC_DO_NOT_CONFIGURE
+};
+
+struct platform_data_t
+    tfm_peripheral_FF_TEST_DRIVER_PARTITION_MMIO = {
+        .periph_start = FF_TEST_DRIVER_PARTITION_MMIO_START,
+        .periph_limit = FF_TEST_DRIVER_PARTITION_MMIO_END,
+        .periph_ppc_mask = AC_DO_NOT_CONFIGURE
+};
+#endif
+
+/*------------------- SAU/IDAU configuration functions -----------------------*/
+void sau_and_idau_cfg(void)
+{
+    /* Ensure all memory accesses are completed */
+    __DMB();
+    #if 0 /* Bootrom set to be secure temporary */
+    /* Configures SAU regions to be non-secure */
+    /* Configure Bootrom */
+    SAU->RNR = 0;
+    SAU->RBAR = (ROM_BASE & SAU_RBAR_BADDR_Msk);
+    SAU->RLAR = ((ROM_BASE + 0x7E00 - 1) & SAU_RLAR_LADDR_Msk)
+                | SAU_RLAR_ENABLE_Msk;
+
+    /* Configure Bootrom SGs */
+    SAU->RNR = 1;
+    SAU->RBAR = ((ROM_BASE + 0x7E00) & SAU_RBAR_BADDR_Msk);
+    SAU->RLAR = ((ROM_BASE + 0x7FFF) & SAU_RLAR_LADDR_Msk)
+                | SAU_RLAR_ENABLE_Msk | SAU_RLAR_NSC_Msk;
+    #endif
+
+    /* Configures veneers region to be non-secure callable */
+    SAU->RNR  = 2;
+    SAU->RBAR = (memory_regions.veneer_base & SAU_RBAR_BADDR_Msk);
+    SAU->RLAR = (memory_regions.veneer_limit & SAU_RLAR_LADDR_Msk)
+                | SAU_RLAR_ENABLE_Msk | SAU_RLAR_NSC_Msk;
+
+    /* Configure Non-Secure partition in flash */
+    SAU->RNR = 3;
+    SAU->RBAR = (memory_regions.non_secure_partition_base
+                 & SAU_RBAR_BADDR_Msk);
+    SAU->RLAR = (memory_regions.non_secure_partition_limit
+                  & SAU_RLAR_LADDR_Msk) | SAU_RLAR_ENABLE_Msk;
+
+    /* Configure the rest of the address map up to PPB */
+    SAU->RNR = 4;
+    SAU->RBAR = (SRAM4_BASE & SAU_RBAR_BADDR_Msk);
+    SAU->RLAR = ((PPB_BASE - 1) & SAU_RLAR_LADDR_Msk)
+                | SAU_RLAR_ENABLE_Msk;
+
+    /* Turn off unused bootrom region */
+    SAU->RNR = 7;
+    SAU->RBAR = 0;
+    SAU->RLAR = 0;
+
+    /* Enables SAU */
+    TZ_SAU_Enable();
+    /* Add barriers to assure the SAU configuration is done before continue
+     * the execution.
+     */
+    __DSB();
+    __ISB();
+}
+
+enum tfm_plat_err_t bus_filter_cfg(void)
+{
+    enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
+    uint32_t c0_c1_unpriv_periph_offsets[] = {AC_SRAM0,
+                AC_SRAM1, AC_SRAM2, AC_SRAM3};
+    uint8_t nbr_of_c0_c1_unpriv_periphs;
+    uint32_t c0_unpriv_periph_offsets[] = {AC_SYSCFG, AC_CLOCKS_BANK_DEFAULT,
+                AC_RSM, AC_BUSCTRL, AC_OTP, AC_POWMAN, AC_TRNG, AC_XOSC,
+                AC_ROSC, AC_PLL_SYS, AC_PLL_USB, AC_TICKS, AC_XIP_CTRL,
+                AC_XIP_QMI};
+    uint8_t nbr_of_c0_unpriv_periphs;
+    uint32_t ns_priv_periph_offsets[] = {AC_ROM, AC_XIP_MAIN, AC_SRAM4,
+                AC_SRAM5, AC_SRAM6, AC_SRAM7, AC_SRAM8, AC_SRAM9, AC_DMA,
+                AC_USBCTRL, AC_PIO0, AC_PIO1, AC_PIO2, AC_CORESIGHT_TRACE,
+                AC_CORESIGHT_PERIPH, AC_SYSINFO, AC_RESETS, AC_IO_BANK0,
+                AC_IO_BANK1, AC_PADS_BANK0, AC_PADS_QSPI, AC_ADC0, AC_HSTX,
+                AC_I2C0, AC_I2C1, AC_PWM, AC_SPI0, AC_SPI1, AC_TIMER0,
+                AC_TIMER1, AC_UART0, AC_UART1, AC_TBMAN, AC_SHA256, AC_WATCHDOG,
+                AC_XIP_AUX};
+    uint8_t nbr_of_ns_periphs;
+    uint32_t temp_addr;
+
+    nbr_of_c0_c1_unpriv_periphs = sizeof(c0_c1_unpriv_periph_offsets) /
+        sizeof(c0_c1_unpriv_periph_offsets[0]);
+    nbr_of_c0_unpriv_periphs = sizeof(c0_unpriv_periph_offsets) /
+        sizeof(c0_unpriv_periph_offsets[0]);
+    nbr_of_ns_periphs = sizeof(ns_priv_periph_offsets) /
+        sizeof(ns_priv_periph_offsets[0]);
+
+    /* Probably worth doing a software reset of access ctrl before setup */
+    accessctrl_hw->cfgreset = ACCESSCTRL_PASSWORD_BITS  | 0x1;
+
+    accessctrl_hw->gpio_nsmask[0] = 0xFFFFFFFC;
+    accessctrl_hw->gpio_nsmask[1] = 0xFF00FFFF;
+
+    /* Peripherals controlled by Secure Core0 and Core1 */
+    for (uint8_t i = 0; i < nbr_of_c0_c1_unpriv_periphs; i++){
+        temp_addr = ACCESSCTRL_BASE + c0_c1_unpriv_periph_offsets[i];
+         REG_RW(temp_addr) = ACCESSCTRL_S_UNPRIV_C0_C1 |
+            ACCESSCTRL_PASSWORD_BITS;
+        if (REG_RW(temp_addr) != ACCESSCTRL_S_UNPRIV_C0_C1) {
+            err = TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    /* Peripherals controlled by Secure Core0 */
+    for (uint8_t i = 0; i < nbr_of_c0_unpriv_periphs; i++){
+        temp_addr = ACCESSCTRL_BASE + c0_unpriv_periph_offsets[i];
+         REG_RW(temp_addr) = ACCESSCTRL_S_UNPRIV_C0 |
+            ACCESSCTRL_PASSWORD_BITS;
+        if (REG_RW(temp_addr) != ACCESSCTRL_S_UNPRIV_C0) {
+            err = TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    /* Peripherals accessable to all bus actors */
+    for (uint8_t i = 0; i < nbr_of_ns_periphs; i++){
+        temp_addr = ACCESSCTRL_BASE + ns_priv_periph_offsets[i];
+         REG_RW(temp_addr) = ACCESSCTRL_NS_PRIV |
+            ACCESSCTRL_PASSWORD_BITS;
+        if (REG_RW(temp_addr) != ACCESSCTRL_NS_PRIV) {
+            err = TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+    }
+
+    /* Lock setings for every actor except Core0, only hard reset can clear
+       this. Core0 must retain control for mmio control. */
+    accessctrl_hw->lock = ACCESSCTRL_PASSWORD_BITS  | 0x6;
+
+    return err;
+}
+
+void access_ctrl_configure_to_secure_privileged(access_ctrl_reg_offset offset)
+{
+    if (offset != AC_DO_NOT_CONFIGURE){
+        REG_RW(ACCESSCTRL_BASE + offset) =
+            ACCESSCTRL_S_PRIV_C0 | ACCESSCTRL_PASSWORD_BITS;
+    }
+}
+
+void access_ctrl_configure_to_secure_unprivileged(access_ctrl_reg_offset offset)
+{
+    if (offset != AC_DO_NOT_CONFIGURE){
+        REG_RW(ACCESSCTRL_BASE + offset) =
+            ACCESSCTRL_S_UNPRIV_C0 | ACCESSCTRL_PASSWORD_BITS;
+    }
+}
+
+enum tfm_plat_err_t dma_security_config(void)
+{
+    /* Configure every DMA channel as Nonsecure Privileged since TF-M uses no DMA */
+    for (int i=0; i<16; i++){
+        REG_RW(DMA_BASE + DMA_SECCFG_CH0_OFFSET + (i * 4)) =
+            DMA_SECCFG_CH0_P_BITS;
+    }
+
+    /* Configure DMA MPU to mirror SAU settings */
+    /* Unmapped address regions default to SP */
+    dma_hw->mpu_ctrl = DMA_MPU_CTRL_NS_HIDE_ADDR_BITS | DMA_MPU_CTRL_S_BITS |
+                       DMA_MPU_CTRL_P_BITS;
+
+    /* Configure MPU regions */
+    dma_hw->mpu_region[0].bar = (memory_regions.veneer_base &
+                                 DMA_MPU_BAR0_BITS);
+    dma_hw->mpu_region[0].lar = (memory_regions.veneer_limit &
+                                 DMA_MPU_LAR0_ADDR_BITS) |
+                                DMA_MPU_LAR0_P_BITS | DMA_MPU_LAR0_EN_BITS;
+
+    dma_hw->mpu_region[1].bar = (memory_regions.non_secure_partition_base &
+                                 DMA_MPU_BAR0_BITS);
+    dma_hw->mpu_region[1].lar = (memory_regions.veneer_limit &
+                                 DMA_MPU_LAR0_ADDR_BITS) |
+                                DMA_MPU_LAR0_P_BITS | DMA_MPU_LAR0_EN_BITS;
+
+    dma_hw->mpu_region[2].bar = (SRAM4_BASE & DMA_MPU_BAR0_BITS);
+    dma_hw->mpu_region[2].lar = ((PPB_BASE - 1) & DMA_MPU_LAR0_ADDR_BITS) |
+                                DMA_MPU_LAR0_P_BITS | DMA_MPU_LAR0_EN_BITS;
+
+    dma_hw->mpu_region[3].bar = 0;
+    dma_hw->mpu_region[3].lar = 0;
+
+    dma_hw->mpu_region[4].bar = 0;
+    dma_hw->mpu_region[4].lar = 0;
+
+    dma_hw->mpu_region[5].bar = 0;
+    dma_hw->mpu_region[5].lar = 0;
+
+    dma_hw->mpu_region[6].bar = 0;
+    dma_hw->mpu_region[6].lar = 0;
+
+    dma_hw->mpu_region[7].bar = 0;
+    dma_hw->mpu_region[7].lar = 0;
+
+    return TFM_PLAT_ERR_SUCCESS;
+}
+
diff --git a/platform/ext/target/rpi/rp2350/target_cfg.h b/platform/ext/target/rpi/rp2350/target_cfg.h
new file mode 100644
index 0000000..3719df6
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/target_cfg.h
@@ -0,0 +1,114 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __TARGET_CFG_H__
+#define __TARGET_CFG_H__
+
+#include <stdint.h>
+
+#define TFM_DRIVER_STDIO    driver_usart0
+#define NS_DRIVER_STDIO     driver_usart0
+
+/**
+ * \brief Defines the word offsets of Slave Peripheral Protection Controller
+ *        Registers
+ */
+typedef enum
+{
+    PPC_SP_DO_NOT_CONFIGURE = -1,
+} ppc_bank_t;
+
+typedef enum
+{
+    AC_LOCK = 0x0,
+    AC_FORCE_CORE_NS = 0x4,
+    AC_CFGRESET = 0x8,
+    AC_GPIO_NSMASK0 = 0xC,
+    AC_GPIO_NSMASK1 = 0x10,
+    AC_ROM = 0x14,
+    AC_XIP_MAIN = 0x18,
+    AC_SRAM0 = 0x1C,
+    AC_SRAM1 = 0x20,
+    AC_SRAM2 = 0x24,
+    AC_SRAM3 = 0x28,
+    AC_SRAM4 = 0x2C,
+    AC_SRAM5 = 0x30,
+    AC_SRAM6 = 0x34,
+    AC_SRAM7 = 0x38,
+    AC_SRAM8 = 0x3C,
+    AC_SRAM9 = 0x40,
+    AC_DMA = 0x44,
+    AC_USBCTRL = 0x48,
+    AC_PIO0 = 0x4C,
+    AC_PIO1 = 0x50,
+    AC_PIO2 = 0x54,
+    AC_CORESIGHT_TRACE = 0x58,
+    AC_CORESIGHT_PERIPH = 0x5C,
+    AC_SYSINFO = 0x60,
+    AC_RESETS = 0x64,
+    AC_IO_BANK0 = 0x68,
+    AC_IO_BANK1 = 0x6C,
+    AC_PADS_BANK0 = 0x70,
+    AC_PADS_QSPI = 0x74,
+    AC_BUSCTRL = 0x78,
+    AC_ADC0 = 0x7C,
+    AC_HSTX = 0x80,
+    AC_I2C0 = 0x84,
+    AC_I2C1 = 0x88,
+    AC_PWM = 0x8C,
+    AC_SPI0 = 0x90,
+    AC_SPI1 = 0x94,
+    AC_TIMER0 = 0x98,
+    AC_TIMER1 = 0x9C,
+    AC_UART0 = 0xA0,
+    AC_UART1 = 0xA4,
+    AC_OTP = 0xA8,
+    AC_TBMAN = 0xAC,
+    AC_POWMAN = 0xB0,
+    AC_TRNG = 0xB4,
+    AC_SHA256 = 0xB8,
+    AC_SYSCFG = 0xBC,
+    AC_CLOCKS_BANK_DEFAULT = 0xC0,
+    AC_XOSC = 0xC4,
+    AC_ROSC = 0xC8,
+    AC_PLL_SYS = 0xCC,
+    AC_PLL_USB = 0xD0,
+    AC_TICKS = 0xD4,
+    AC_WATCHDOG = 0xD8,
+    AC_RSM = 0xDC,
+    AC_XIP_CTRL = 0xE0,
+    AC_XIP_QMI = 0xE4,
+    AC_XIP_AUX = 0xE8,
+    AC_DO_NOT_CONFIGURE = 0xFFFF,
+} access_ctrl_reg_offset;
+
+/**
+ * \brief Initialize SAU.
+ */
+void sau_and_idau_cfg(void);
+
+/**
+ * \brief Configure access control for bus endpoints.
+ */
+enum tfm_plat_err_t bus_filter_cfg(void);
+
+/**
+ * \brief Configure DMA channels' security
+ */
+enum tfm_plat_err_t dma_security_config(void);
+
+/**
+ * \brief Configure bus endpoint to be secure privileged accessible for core0
+ */
+void access_ctrl_configure_to_secure_privileged(access_ctrl_reg_offset offset);
+
+
+/**
+ * \brief Configure bus endpoint to be secure unprivileged accessible for core0
+ */
+void access_ctrl_configure_to_secure_unprivileged(access_ctrl_reg_offset offset);
+
+#endif /* __TARGET_CFG_H__ */
diff --git a/platform/ext/target/rpi/rp2350/tests/psa_arch_tests_config.cmake b/platform/ext/target/rpi/rp2350/tests/psa_arch_tests_config.cmake
new file mode 100644
index 0000000..6ae2b7b
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tests/psa_arch_tests_config.cmake
@@ -0,0 +1,9 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+
+# Paramters for PSA API tests
+
+set(PSA_API_TEST_TARGET              rp2350     CACHE STRING  "PSA_API_TARGET name")
diff --git a/platform/ext/target/rpi/rp2350/tests/tfm_tests_config.cmake b/platform/ext/target/rpi/rp2350/tests/tfm_tests_config.cmake
new file mode 100644
index 0000000..3fff55d
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tests/tfm_tests_config.cmake
@@ -0,0 +1,10 @@
+#-------------------------------------------------------------------------------
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+#-------------------------------------------------------------------------------
+# Make FLIH IRQ test as the default IRQ test on RP2350
+set(TEST_NS_SLIH_IRQ                  OFF   CACHE BOOL    "Whether to build NS regression Second-Level Interrupt Handling tests")
+
+set(PLATFORM_SLIH_IRQ_TEST_SUPPORT    ON)
+set(PLATFORM_FLIH_IRQ_TEST_SUPPORT    ON)
diff --git a/platform/ext/target/rpi/rp2350/tfm_builtin_key_ids.h b/platform/ext/target/rpi/rp2350/tfm_builtin_key_ids.h
new file mode 100644
index 0000000..ec842ae
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_builtin_key_ids.h
@@ -0,0 +1,31 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __TFM_BUILTIN_KEY_IDS_H__
+#define __TFM_BUILTIN_KEY_IDS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief The persistent key identifiers for TF-M builtin keys.
+ *
+ * The value of TFM_BUILTIN_KEY_ID_MIN (and therefore of the whole range) is
+ * completely arbitrary except for being inside the PSA builtin keys range.
+ *
+ */
+enum tfm_key_id_builtin_t {
+    TFM_BUILTIN_KEY_ID_MIN = 0x7FFF815Bu,
+    TFM_BUILTIN_KEY_ID_HUK,
+    TFM_BUILTIN_KEY_ID_IAK,
+    TFM_BUILTIN_KEY_ID_MAX = 0x7FFF817Bu,
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TFM_BUILTIN_KEY_IDS_H__ */
diff --git a/platform/ext/target/rpi/rp2350/tfm_hal_isolation_rp2350.c b/platform/ext/target/rpi/rp2350/tfm_hal_isolation_rp2350.c
new file mode 100644
index 0000000..eda91fa
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_hal_isolation_rp2350.c
@@ -0,0 +1,469 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include <arm_cmse.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include "array.h"
+#include "tfm_hal_device_header.h"
+#include "region.h"
+#include "armv8m_mpu.h"
+#include "target_cfg.h"
+#include "tfm_hal_defs.h"
+#include "tfm_hal_isolation.h"
+#include "tfm_peripherals_def.h"
+#include "load/spm_load_api.h"
+
+#define PROT_BOUNDARY_VAL \
+    ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
+/* Boundary handle binding macros. */
+#define HANDLE_ATTR_PRIV_POS            1U
+#define HANDLE_ATTR_PRIV_MASK           (0x1UL << HANDLE_ATTR_PRIV_POS)
+#define HANDLE_ATTR_NS_POS              0U
+#define HANDLE_ATTR_NS_MASK             (0x1UL << HANDLE_ATTR_NS_POS)
+
+#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+static uint32_t n_configured_regions = 0;
+
+#ifdef CONFIG_TFM_USE_TRUSTZONE
+REGION_DECLARE(Image$$, ER_VENEER, $$Base);
+REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
+#endif /* CONFIG_TFM_USE_TRUSTZONE */
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
+REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
+REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
+#ifdef CONFIG_TFM_PARTITION_META
+REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit);
+#endif /* CONFIG_TFM_PARTITION_META */
+
+#define ARM_MPU_NON_TRANSIENT        ( 1U )
+#define ARM_MPU_TRANSIENT            ( 0U )
+#define ARM_MPU_WRITE_BACK           ( 1U )
+#define ARM_MPU_WRITE_THROUGH        ( 0U )
+#define ARM_MPU_READ_ALLOCATE        ( 1U )
+#define ARM_MPU_NON_READ_ALLOCATE    ( 0U )
+#define ARM_MPU_WRITE_ALLOCATE       ( 1U )
+#define ARM_MPU_NON_WRITE_ALLOCATE   ( 0U )
+#define ARM_MPU_READ_ONLY            ( 1U )
+#define ARM_MPU_READ_WRITE           ( 0U )
+#define ARM_MPU_UNPRIVILEGED         ( 1U )
+#define ARM_MPU_PRIVILEGED           ( 0U )
+#define ARM_MPU_EXECUTE_NEVER        ( 1U )
+#define ARM_MPU_EXECUTE_OK           ( 0U )
+#define ARM_MPU_PRIVILEGE_EXECUTE_NEVER  ( 1U )
+#define ARM_MPU_PRIVILEGE_EXECUTE_OK     ( 0U )
+#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
+
+enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(
+                                            uintptr_t *p_spm_boundary)
+{
+#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+const ARM_MPU_Region_t mpu_region_attributes[] = {
+#ifdef CONFIG_TFM_USE_TRUSTZONE
+    /* TFM Veneer region (Bootrom SGs are not included)
+     * Region Number 0, Non-shareable, Read-Only, Non-Privileged, Executable,
+     * Privilege Executable - if PXN available, Attribute set: 0
+     */
+    {
+        ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, ER_VENEER, $$Base),
+                     ARM_MPU_SH_NON,
+                     ARM_MPU_READ_ONLY,
+                     ARM_MPU_UNPRIVILEGED,
+                     ARM_MPU_EXECUTE_OK),
+        #ifdef TFM_PXN_ENABLE
+        ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
+                         ARM_MPU_PRIVILEGE_EXECUTE_OK,
+                         0)
+        #else
+        ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
+                     0)
+        #endif
+    },
+#endif /* CONFIG_TFM_USE_TRUSTZONE */
+    /* TFM Core unprivileged code region
+     * Region Number 1, Non-shareable, Read-Only, Non-Privileged, Executable,
+     * Privilege Executable - if PXN available, Attribute set: 0
+     */
+    {
+        ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base),
+                     ARM_MPU_SH_NON,
+                     ARM_MPU_READ_ONLY,
+                     ARM_MPU_UNPRIVILEGED,
+                     ARM_MPU_EXECUTE_OK),
+        #ifdef TFM_PXN_ENABLE
+        ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1,
+                         ARM_MPU_PRIVILEGE_EXECUTE_OK,
+                         0)
+        #else
+        ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1,
+                     0)
+        #endif
+    },
+    /* RO region
+     * Region Number 2, Non-shareable, Read-Only, Non-Privileged, Executable,
+     * PXN depends on isolation level, Attribute set: 0
+     */
+    {
+        ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base),
+                     ARM_MPU_SH_NON,
+                     ARM_MPU_READ_ONLY,
+                     ARM_MPU_UNPRIVILEGED,
+                     ARM_MPU_EXECUTE_OK),
+        #ifdef TFM_PXN_ENABLE
+        ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1,
+            #if TFM_ISOLATION_LEVEL == 1
+                         ARM_MPU_PRIVILEGE_EXECUTE_OK,
+            #else
+                         ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
+            #endif
+                         0)
+        #else
+        ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1,
+                     0)
+        #endif
+    },
+    /* RW, ZI and stack as one region
+     * Region Number 3, Non-shareable, Read-Write, Non-Privileged, Execute Never
+     * Attribute set: 1, Privilege Execute Never - if PXN available
+     */
+    {
+        ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
+                     ARM_MPU_SH_NON,
+                     ARM_MPU_READ_WRITE,
+                     ARM_MPU_UNPRIVILEGED,
+                     ARM_MPU_EXECUTE_NEVER),
+        #ifdef TFM_PXN_ENABLE
+        ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1,
+                         ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
+                         1)
+        #else
+        ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1,
+                     1)
+        #endif
+    },
+#ifdef CONFIG_TFM_PARTITION_META
+    /* TFM partition metadata pointer region
+     * Region Number 4, Non-shareable, Read-Write, Non-Privileged, Execute Never
+     * Attribute set: 1, Privilege Execute Never - if PXN available
+     */
+    {
+        ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
+                     ARM_MPU_SH_NON,
+                     ARM_MPU_READ_WRITE,
+                     ARM_MPU_UNPRIVILEGED,
+                     ARM_MPU_EXECUTE_NEVER),
+        #ifdef TFM_PXN_ENABLE
+        ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1,
+                         ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
+                         1)
+        #else
+        ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1,
+                     1)
+        #endif
+    },
+#endif
+};
+    ARM_MPU_Region_t localcfg;
+#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
+
+    /* Set up isolation boundaries between SPE and NSPE */
+    sau_and_idau_cfg();
+    if (bus_filter_cfg() != TFM_PLAT_ERR_SUCCESS) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+
+    if (dma_security_config() != TFM_PLAT_ERR_SUCCESS) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+
+    /* Set up static isolation boundaries inside SPE */
+#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+    int32_t i;
+
+    uint32_t mpu_region_num =
+        (MPU ->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+
+    if (mpu_region_num < ARRAY_SIZE(mpu_region_attributes)) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+
+    /* Turn off MPU during configuration */
+    if ((MPU->CTRL & MPU_CTRL_ENABLE_Msk)) {
+        ARM_MPU_Disable();
+    }
+    /* Disable all regions */
+    for (i = 0; i < mpu_region_num; i++) {
+        ARM_MPU_ClrRegion(i);
+    }
+
+    /* Configure attribute registers
+     * Attr0 : Normal memory, Inner/Outer Cacheable, Write-Trough Read-Allocate
+     */
+    ARM_MPU_SetMemAttr(0,
+                   ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
+                                                     ARM_MPU_WRITE_THROUGH,
+                                                     ARM_MPU_READ_ALLOCATE,
+                                                     ARM_MPU_NON_WRITE_ALLOCATE),
+                                ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
+                                                     ARM_MPU_WRITE_THROUGH,
+                                                     ARM_MPU_READ_ALLOCATE,
+                                                     ARM_MPU_NON_WRITE_ALLOCATE)));
+    /* Attr1 : Normal memory, Inner/Outer Cacheable, Write-Back R-W Allocate */
+    ARM_MPU_SetMemAttr(1,
+                    ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
+                                                     ARM_MPU_WRITE_BACK,
+                                                     ARM_MPU_READ_ALLOCATE,
+                                                     ARM_MPU_WRITE_ALLOCATE),
+                                ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
+                                                     ARM_MPU_WRITE_BACK,
+                                                     ARM_MPU_READ_ALLOCATE,
+                                                     ARM_MPU_WRITE_ALLOCATE)));
+    /* Attr2 : Device memory, nGnRE */
+    ARM_MPU_SetMemAttr(2,
+                       ARM_MPU_ATTR(ARM_MPU_ATTR_DEVICE,
+                                    ARM_MPU_ATTR_DEVICE_nGnRE));
+
+    /* Configure regions */
+    /* Note: CMSIS MPU API clears the lower 5 address bits without check */
+    for (i = 0; i < ARRAY_SIZE(mpu_region_attributes); i++) {
+        localcfg.RBAR = mpu_region_attributes[i].RBAR;
+        localcfg.RLAR = mpu_region_attributes[i].RLAR;
+        ARM_MPU_SetRegion(i, localcfg.RBAR, localcfg.RLAR);
+    }
+    n_configured_regions = i;
+
+    /* Enable MPU with the above configurations. Allow default memory map for
+     * privileged software and enable MPU during HardFault and NMI handlers.
+     */
+    ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
+#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
+
+    *p_spm_boundary = (uintptr_t)PROT_BOUNDARY_VAL;
+
+    return TFM_HAL_SUCCESS;
+}
+
+/*
+ * Implementation of tfm_hal_bind_boundary():
+ *
+ * The API encodes some attributes into a handle and returns it to SPM.
+ * The attributes include isolation boundaries, privilege, and MMIO information.
+ * When scheduler switches running partitions, SPM compares the handle between
+ * partitions to know if boundary update is necessary. If update is required,
+ * SPM passes the handle to platform to do platform settings and update
+ * isolation boundaries.
+ */
+enum tfm_hal_status_t tfm_hal_bind_boundary(
+                                    const struct partition_load_info_t *p_ldinf,
+                                    uintptr_t *p_boundary)
+{
+    uint32_t i, j;
+    bool privileged;
+    bool ns_agent_tz;
+    uint32_t partition_attrs = 0;
+    const struct asset_desc_t *p_asset;
+    struct platform_data_t *plat_data_ptr;
+    const uintptr_t* mmio_list;
+    size_t mmio_list_length;
+
+#if TFM_ISOLATION_LEVEL == 2
+    ARM_MPU_Region_t local_mpu_region;
+    uint32_t mpu_region_num;
+#endif
+    if (!p_ldinf || !p_boundary) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+
+#if TFM_ISOLATION_LEVEL == 1
+    privileged = true;
+#else
+    privileged = IS_PSA_ROT(p_ldinf);
+#endif
+
+    ns_agent_tz = IS_NS_AGENT_TZ(p_ldinf);
+    p_asset = LOAD_INFO_ASSET(p_ldinf);
+
+    get_partition_named_mmio_list(&mmio_list, &mmio_list_length);
+
+    /*
+     * Validate if the named MMIO of partition is allowed by the platform.
+     * Otherwise, skip validation.
+     *
+     * NOTE: Need to add validation of numbered MMIO if platform requires.
+     */
+    for (i = 0; i < p_ldinf->nassets; i++) {
+        if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
+            continue;
+        }
+        for (j = 0; j < mmio_list_length; j++) {
+            if (p_asset[i].dev.dev_ref == mmio_list[j]) {
+                break;
+            }
+        }
+
+        if (j == mmio_list_length) {
+            /* The MMIO asset is not in the allowed list of platform. */
+            return TFM_HAL_ERROR_GENERIC;
+        }
+        /* Assume sec and priv settings are required even under level 1 */
+        plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
+                                         struct platform_data_t *);
+
+        if (plat_data_ptr->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
+            if (privileged) {
+                access_ctrl_configure_to_secure_privileged(
+                    (access_ctrl_reg_offset)plat_data_ptr->periph_ppc_mask);
+            } else {
+                access_ctrl_configure_to_secure_unprivileged(
+                    (access_ctrl_reg_offset)plat_data_ptr->periph_ppc_mask);
+            }
+        }
+#if TFM_ISOLATION_LEVEL == 2
+        /*
+         * Static boundaries are set. Set up MPU region for MMIO.
+         * Setup regions for unprivileged assets only.
+         */
+        if (!privileged) {
+            mpu_region_num =
+                (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+
+            /* There is a limited number of available MPU regions in v8M */
+            if (mpu_region_num <= n_configured_regions) {
+                return TFM_HAL_ERROR_GENERIC;
+            }
+            if ((plat_data_ptr->periph_start & ~MPU_RBAR_BASE_Msk) != 0) {
+                return TFM_HAL_ERROR_GENERIC;
+            }
+            if ((plat_data_ptr->periph_limit & ~MPU_RLAR_LIMIT_Msk) != 0x1F) {
+                return TFM_HAL_ERROR_GENERIC;
+            }
+
+            /* Turn off MPU during configuration */
+            if (MPU->CTRL & MPU_CTRL_ENABLE_Msk) {
+                ARM_MPU_Disable();
+            }
+
+            /* Assemble region base and limit address register contents. */
+            local_mpu_region.RBAR = ARM_MPU_RBAR(plat_data_ptr->periph_start,
+                                                 ARM_MPU_SH_NON,
+                                                 ARM_MPU_READ_WRITE,
+                                                 ARM_MPU_UNPRIVILEGED,
+                                                 ARM_MPU_EXECUTE_NEVER);
+            /* Attr2 contains required attribute set for device regions */
+            #ifdef TFM_PXN_ENABLE
+            local_mpu_region.RLAR = ARM_MPU_RLAR_PXN(plat_data_ptr->periph_limit,
+                                                     ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
+                                                     2);
+            #else
+            local_mpu_region.RLAR = ARM_MPU_RLAR(plat_data_ptr->periph_limit,
+                                                 2);
+            #endif
+
+            /* Configure device mpu region */
+            ARM_MPU_SetRegion(n_configured_regions,
+                              local_mpu_region.RBAR,
+                              local_mpu_region.RLAR);
+
+            n_configured_regions++;
+
+            /* Enable MPU with the new region added */
+            ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
+        }
+#endif
+    }
+
+    partition_attrs = ((uint32_t)privileged << HANDLE_ATTR_PRIV_POS) &
+                        HANDLE_ATTR_PRIV_MASK;
+    partition_attrs |= ((uint32_t)ns_agent_tz << HANDLE_ATTR_NS_POS) &
+                        HANDLE_ATTR_NS_MASK;
+    *p_boundary = (uintptr_t)partition_attrs;
+
+    return TFM_HAL_SUCCESS;
+}
+
+enum tfm_hal_status_t tfm_hal_activate_boundary(
+                             const struct partition_load_info_t *p_ldinf,
+                             uintptr_t boundary)
+{
+    CONTROL_Type ctrl;
+    bool privileged = !!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK);
+
+    /* Privileged level is required to be set always */
+    ctrl.w = __get_CONTROL();
+    ctrl.b.nPRIV = privileged ? 0 : 1;
+    __set_CONTROL(ctrl.w);
+
+    return TFM_HAL_SUCCESS;
+}
+
+enum tfm_hal_status_t tfm_hal_memory_check(uintptr_t boundary, uintptr_t base,
+                                           size_t size, uint32_t access_type)
+{
+    int flags = 0;
+
+    /* If size is zero, this indicates an empty buffer and base is ignored */
+    if (size == 0) {
+        return TFM_HAL_SUCCESS;
+    }
+
+    if (!base) {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
+
+    if ((access_type & TFM_HAL_ACCESS_READWRITE) == TFM_HAL_ACCESS_READWRITE) {
+        flags |= CMSE_MPU_READWRITE;
+    } else if (access_type & TFM_HAL_ACCESS_READABLE) {
+        flags |= CMSE_MPU_READ;
+    } else {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
+
+    if (access_type & TFM_HAL_ACCESS_NS) {
+        flags |= CMSE_NONSECURE;
+    }
+
+    if (!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK)) {
+        flags |= CMSE_MPU_UNPRIV;
+    }
+
+    /* This check is only done for ns_agent_tz */
+    if ((uint32_t)boundary & HANDLE_ATTR_NS_MASK) {
+        CONTROL_Type ctrl;
+        ctrl.w = __TZ_get_CONTROL_NS();
+        if (ctrl.b.nPRIV == 1) {
+            flags |= CMSE_MPU_UNPRIV;
+        } else {
+            flags &= ~CMSE_MPU_UNPRIV;
+        }
+        flags |= CMSE_NONSECURE;
+    }
+
+    if (cmse_check_address_range((void *)base, size, flags) != NULL) {
+        return TFM_HAL_SUCCESS;
+    } else {
+        return TFM_HAL_ERROR_MEM_FAULT;
+    }
+}
+
+bool tfm_hal_boundary_need_switch(uintptr_t boundary_from,
+                                  uintptr_t boundary_to)
+{
+    if (boundary_from == boundary_to) {
+        return false;
+    }
+
+    if (((uint32_t)boundary_from & HANDLE_ATTR_PRIV_MASK) &&
+        ((uint32_t)boundary_to & HANDLE_ATTR_PRIV_MASK)) {
+        return false;
+    }
+    return true;
+}
diff --git a/platform/ext/target/rpi/rp2350/tfm_hal_mailbox.c b/platform/ext/target/rpi/rp2350/tfm_hal_mailbox.c
new file mode 100644
index 0000000..41b93eb
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_hal_mailbox.c
@@ -0,0 +1,101 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_hal_mailbox.h"
+#include "tfm_multi_core.h"
+#include "tfm_hal_interrupt.h"
+#include "tfm_peripherals_def.h"
+#include "hardware/irq.h"
+#include "interrupt.h"
+
+#include "platform_multicore.h"
+
+#include "pico/multicore.h"
+
+static struct irq_t mbox_irq_info = {0};
+
+int32_t tfm_mailbox_hal_init(struct secure_mailbox_queue_t *s_queue)
+{
+    struct mailbox_init_t *ns_init = NULL;
+
+    multicore_ns_fifo_push_blocking_inline(NS_MAILBOX_INIT);
+
+    ns_init = (struct mailbox_init_t *) multicore_ns_fifo_pop_blocking_inline();
+
+    /*
+     * FIXME
+     * Necessary sanity check of the address of NPSE mailbox queue should
+     * be implemented there.
+     */
+    if (ns_init->slot_count > NUM_MAILBOX_QUEUE_SLOT) {
+        return MAILBOX_INIT_ERROR;
+    }
+
+    s_queue->ns_status = ns_init->status;
+    s_queue->ns_slot_count = ns_init->slot_count;
+    s_queue->ns_slots = ns_init->slots;
+
+    multicore_ns_fifo_push_blocking_inline(S_MAILBOX_READY);
+
+    return MAILBOX_SUCCESS;
+}
+
+int32_t tfm_mailbox_hal_notify_peer(void)
+{
+    multicore_ns_fifo_push_blocking_inline(NOTIFY_FROM_CORE0);
+    return MAILBOX_SUCCESS;
+}
+
+void tfm_mailbox_hal_enter_critical(void)
+{
+    /* Reading a spinlock register attempts to claim it, returning nonzero
+     * if the claim was successful and 0 if unsuccessful */
+    while(!*MAILBOX_SPINLOCK);
+    return;
+}
+
+void tfm_mailbox_hal_exit_critical(void)
+{
+    /* Writing to a spinlock register releases it */
+    *MAILBOX_SPINLOCK = 0x1u;
+    return;
+}
+
+/* Platform specific inter-processor communication interrupt handler. */
+void SIO_IRQ_FIFO_NS_IRQHandler(void)
+{
+    /*
+     * SPM will send a MAILBOX_SIGNAL to the corresponding partition
+     * indicating that a message has arrived and can be processed.
+     */
+    uint32_t msg;
+    if (multicore_ns_fifo_rvalid())
+    {
+        msg = multicore_ns_fifo_pop_blocking_inline();
+        if (msg == NOTIFY_FROM_CORE1) {
+            spm_handle_interrupt(mbox_irq_info.p_pt, mbox_irq_info.p_ildi);
+        }
+    }
+}
+
+enum tfm_hal_status_t mailbox_irq_init(void *p_pt,
+                                       const struct irq_load_info_t *p_ildi)
+{
+    mbox_irq_info.p_pt = p_pt;
+    mbox_irq_info.p_ildi = p_ildi;
+
+
+    NVIC_SetPriority(SIO_IRQ_FIFO_NS_IRQn, DEFAULT_IRQ_PRIORITY-1);
+    irq_set_exclusive_handler(SIO_IRQ_FIFO_NS, SIO_IRQ_FIFO_NS_IRQHandler);
+
+    if (tfm_multi_core_register_client_id_range(CLIENT_ID_OWNER_MAGIC,
+                                                p_ildi->client_id_base,
+                                                p_ildi->client_id_limit) != 0) {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
+
+    return TFM_HAL_SUCCESS;
+}
\ No newline at end of file
diff --git a/platform/ext/target/rpi/rp2350/tfm_hal_multi_core.c b/platform/ext/target/rpi/rp2350/tfm_hal_multi_core.c
new file mode 100644
index 0000000..ccf8c1c
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_hal_multi_core.c
@@ -0,0 +1,147 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_hal_multi_core.h"
+#include "platform_multicore.h"
+#include "target_cfg.h"
+#include "region_defs.h"
+
+#include "interrupt.h"
+#include "pico/multicore.h"
+#include "hardware/structs/sio.h"
+
+/* Entrypoint function declaration */
+extern void ns_agent_tz_main(uint32_t c_entry);
+
+volatile uint32_t CORE1_RUNNING;
+
+bool multicore_ns_fifo_rvalid(void) {
+    return !!(sio_ns_hw->fifo_st & SIO_FIFO_ST_VLD_BITS);
+}
+
+bool multicore_ns_fifo_wready(void) {
+    return !!(sio_ns_hw->fifo_st & SIO_FIFO_ST_RDY_BITS);
+}
+
+void multicore_ns_fifo_push_blocking_inline(uint32_t data) {
+    /* We wait for the fifo to have some space */
+    while (!multicore_ns_fifo_wready())
+        tight_loop_contents();
+
+    sio_ns_hw->fifo_wr = data;
+
+    /* Fire off an event to the other core */
+    __sev();
+}
+
+uint32_t multicore_ns_fifo_pop_blocking_inline(void) {
+    /* If nothing there yet, we wait for an event first,
+       to try and avoid too much busy waiting */
+    while (!multicore_ns_fifo_rvalid())
+        __wfe();
+
+    return sio_ns_hw->fifo_rd;
+}
+
+static void wait_for_core1_ready(void)
+{
+    uint32_t stage;
+    while (1) {
+        stage = multicore_fifo_pop_blocking();
+        if  (stage == CORE1_S_READY) {
+            break;
+        }
+    }
+}
+
+/* If Core0 wants to write Flash, Core1 must not use it.
+ * As Core1 partly runs from Flash, it must be stopped while Core0 is writing.
+ * The simplest solution is for Core0 to ring Core1's doorbell where we wait out
+ * the flash operation, using spinlock. */
+static void __not_in_flash_func(Core1Doorbell_Handler)() {
+    uint32_t status = 0;
+    /* Prevent IRQs to fire, as their handlers might be in Flash */
+    __ASM volatile ("mrs %0, primask \n cpsid i" : "=r" (status) :: "memory");
+    /* Check if this is the "flash-in-use" doorbell */
+    if (sio_hw->doorbell_in_set & FLASH_DOORBELL_MASK)
+    {
+        /* Clear doorbell */
+        sio_hw->doorbell_in_clr = FLASH_DOORBELL_MASK;
+        /* Wait for Flash to be available, then release it immediately */
+        while(!*FLASH_SPINLOCK);
+        *FLASH_SPINLOCK = 0x1;
+    /* Check if this is the "halt" doorbell */
+    } else if (sio_hw->doorbell_in_set & HALT_DOORBELL_MASK)
+    {
+        /* Clear doorbell */
+        sio_hw->doorbell_in_clr = HALT_DOORBELL_MASK;
+        while (1) {
+            __WFE();
+        }
+    }
+    /* Restore IRQ status */
+    __ASM volatile ("msr primask, %0" :: "r" (status) : "memory");
+}
+
+static void core1_entry(void)
+{
+    __TZ_set_STACKSEAL_S((uint32_t *)__get_MSP());
+    /* Set up isolation boundaries between SPE and NSPE */
+    sau_and_idau_cfg();
+
+    NVIC_SetVector(SIO_IRQ_BELL_IRQn, (uint32_t) Core1Doorbell_Handler);
+    /* Set it to highest priority */
+    NVIC_SetPriority(SIO_IRQ_BELL_IRQn, 0x0);
+    NVIC_EnableIRQ(SIO_IRQ_BELL_IRQn);
+    __enable_irq();
+
+    NVIC_SetTargetState(SIO_IRQ_FIFO_NS_IRQn);
+    multicore_fifo_push_blocking(CORE1_S_READY);
+
+    ns_agent_tz_main(NS_CODE_CORE1_START);
+}
+
+static void boot_s_core(void)
+{
+    CORE1_RUNNING = 0x1;
+    multicore_launch_core1(core1_entry);
+    wait_for_core1_ready();
+}
+
+void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
+{
+    boot_s_core();
+    return;
+}
+
+void tfm_hal_wait_for_ns_cpu_ready(void)
+{
+    uint32_t stage;
+    while (1) {
+        stage = multicore_ns_fifo_pop_blocking_inline();
+        if  (stage == CORE1_NS_READY) {
+            break;
+        }
+    }
+    return;
+}
+
+void tfm_hal_get_secure_access_attr(const void *p, size_t s,
+                                    struct mem_attr_info_t *p_attr)
+{
+    /* Check static memory layout to get memory attributes */
+    tfm_get_secure_mem_region_attr(p, s, p_attr);
+#if TFM_ISOLATION_LEVEL >= 2
+    p_attr->is_mpu_enabled = true;
+#endif
+}
+
+void tfm_hal_get_ns_access_attr(const void *p, size_t s,
+                                struct mem_attr_info_t *p_attr)
+{
+    /* Check static memory layout to get memory attributes */
+    tfm_get_ns_mem_region_attr(p, s, p_attr);
+}
diff --git a/platform/ext/target/rpi/rp2350/tfm_hal_platform.c b/platform/ext/target/rpi/rp2350/tfm_hal_platform.c
new file mode 100644
index 0000000..01d9fc1
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_hal_platform.c
@@ -0,0 +1,127 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_hal_device_header.h"
+#include "tfm_peripherals_def.h"
+#include "common_target_cfg.h"
+#include "tfm_hal_platform.h"
+#include "uart_stdout.h"
+#include "region.h"
+#include "region_defs.h"
+#include "pico/bootrom.h"
+
+#include "hardware/structs/psm.h"
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+#include "platform_multicore.h"
+#include "hardware/structs/sio.h"
+#endif
+
+#if defined(TFM_PARTITION_SLIH_TEST) || defined(TFM_PARTITION_FLIH_TEST)
+#include "hardware/irq.h"
+extern void tfm_plat_test_secure_timer_irq_handler(void);
+#endif
+
+/* The section names come from the scatter file */
+REGION_DECLARE(Load$$LR$$, LR_NS_PARTITION, $$Base);
+REGION_DECLARE(Image$$, ER_VENEER, $$Base);
+REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
+#ifdef BL2
+REGION_DECLARE(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base);
+#endif /* BL2 */
+
+const struct memory_region_limits memory_regions = {
+    .non_secure_code_start =
+        (uint32_t)&REGION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) +
+        BL2_HEADER_SIZE,
+
+    .non_secure_partition_base =
+        (uint32_t)&REGION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base),
+
+    .non_secure_partition_limit =
+        (uint32_t)&REGION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) +
+        NS_PARTITION_SIZE - 1,
+
+    .veneer_base =
+        (uint32_t)&REGION_NAME(Image$$, ER_VENEER, $$Base),
+
+    .veneer_limit =
+        (uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
+
+#ifdef BL2
+    .secondary_partition_base =
+        (uint32_t)&REGION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base),
+
+    .secondary_partition_limit =
+        (uint32_t)&REGION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base) +
+        SECONDARY_PARTITION_SIZE - 1,
+#endif /* BL2 */
+};
+
+extern __NO_RETURN void MemManage_Handler(void);
+extern __NO_RETURN void BusFault_Handler(void);
+extern __NO_RETURN void UsageFault_Handler(void);
+extern __NO_RETURN void SecureFault_Handler(void);
+
+enum tfm_hal_status_t tfm_hal_platform_init(void)
+{
+    NVIC_SetVector(MemoryManagement_IRQn, (uint32_t) MemManage_Handler);
+    NVIC_SetVector(BusFault_IRQn, (uint32_t) BusFault_Handler);
+    NVIC_SetVector(UsageFault_IRQn, (uint32_t) UsageFault_Handler);
+    NVIC_SetVector(SecureFault_IRQn, (uint32_t) SecureFault_Handler);
+
+    stdio_init();
+
+#if defined(TFM_PARTITION_SLIH_TEST) || defined(TFM_PARTITION_FLIH_TEST)
+    irq_set_exclusive_handler(TFM_TIMER0_IRQ, tfm_plat_test_secure_timer_irq_handler);
+#endif
+
+#ifdef PSA_API_TEST_IPC
+    irq_set_exclusive_handler(FF_TEST_UART_IRQ, FF_TEST_UART_IRQ_Handler);
+#endif
+
+    /* Reset everything apart from ROSC and XOSC */
+    hw_set_bits(&psm_hw->wdsel, PSM_WDSEL_BITS & ~(PSM_WDSEL_ROSC_BITS | PSM_WDSEL_XOSC_BITS));
+
+    __enable_irq();
+    return TFM_HAL_SUCCESS;
+}
+
+uint32_t tfm_hal_get_ns_VTOR(void)
+{
+    return memory_regions.non_secure_code_start;
+}
+
+uint32_t tfm_hal_get_ns_MSP(void)
+{
+    return *((uint32_t *)memory_regions.non_secure_code_start);
+}
+
+uint32_t tfm_hal_get_ns_entry_point(void)
+{
+    return *((uint32_t *)(memory_regions.non_secure_code_start + 4));
+}
+
+void tfm_hal_system_reset(void)
+{
+    __disable_irq();
+
+    NVIC_SystemReset();
+}
+
+void tfm_hal_system_halt(void)
+{
+    __disable_irq();
+
+#ifdef TFM_MULTI_CORE_TOPOLOGY
+    /* Signal Core1 to wait for flash */
+    sio_hw->doorbell_out_set = HALT_DOORBELL_MASK;
+#endif
+
+    while (1) {
+        __WFE();
+    }
+
+}
diff --git a/platform/ext/target/rpi/rp2350/tfm_peripherals_def.c b/platform/ext/target/rpi/rp2350/tfm_peripherals_def.c
new file mode 100644
index 0000000..8a32c43
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_peripherals_def.c
@@ -0,0 +1,27 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#include "tfm_peripherals_def.h"
+#include "array.h"
+#include "tfm_hal_device_header.h"
+
+/* Allowed named MMIO of this platform */
+const uintptr_t partition_named_mmio_list[] = {
+    (uintptr_t)TFM_PERIPHERAL_TIMER0,
+    (uintptr_t)TFM_PERIPHERAL_STD_UART,
+#ifdef PSA_API_TEST_IPC
+    (uintptr_t)FF_TEST_UART_REGION,
+    (uintptr_t)FF_TEST_WATCHDOG_REGION,
+    (uintptr_t)FF_TEST_NVMEM_REGION,
+    (uintptr_t)FF_TEST_SERVER_PARTITION_MMIO,
+    (uintptr_t)FF_TEST_DRIVER_PARTITION_MMIO,
+#endif
+};
+
+void get_partition_named_mmio_list(const uintptr_t** list, size_t* length) {
+    *list = partition_named_mmio_list;
+    *length = ARRAY_SIZE(partition_named_mmio_list);
+}
diff --git a/platform/ext/target/rpi/rp2350/tfm_peripherals_def.h b/platform/ext/target/rpi/rp2350/tfm_peripherals_def.h
new file mode 100644
index 0000000..a758cdb
--- /dev/null
+++ b/platform/ext/target/rpi/rp2350/tfm_peripherals_def.h
@@ -0,0 +1,54 @@
+/*
+ *  SPDX-License-Identifier: BSD-3-Clause
+ *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ */
+
+#ifndef __TFM_PERIPHERALS_DEF_H__
+#define __TFM_PERIPHERALS_DEF_H__
+
+#include "hardware/irq.h"
+#include "common_target_cfg.h"
+#include "tfm_hal_device_header.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Quantized default IRQ priority, the value is:
+ * (Number of configurable priority) / 2: (1UL << __NVIC_PRIO_BITS) / 4
+ */
+
+#define DEFAULT_IRQ_PRIORITY     (1UL << (__NVIC_PRIO_BITS - 2))
+
+#define TFM_TIMER0_IRQ           (TIMER0_IRQ_0_IRQn)
+#define MAILBOX_IRQ               SIO_IRQ_FIFO_NS_IRQn
+
+#define FF_TEST_UART_IRQ         (UART0_IRQ)
+extern void FF_TEST_UART_IRQ_Handler(void);
+
+extern struct platform_data_t tfm_peripheral_std_uart;
+extern struct platform_data_t tfm_peripheral_timer0;
+
+#define TFM_PERIPHERAL_STD_UART  (&tfm_peripheral_std_uart)
+#define TFM_PERIPHERAL_TIMER0    (&tfm_peripheral_timer0)
+
+#ifdef PSA_API_TEST_IPC
+extern struct platform_data_t tfm_peripheral_FF_TEST_UART_REGION;
+extern struct platform_data_t tfm_peripheral_FF_TEST_WATCHDOG_REGION;
+extern struct platform_data_t tfm_peripheral_FF_TEST_NVMEM_REGION;
+extern struct platform_data_t tfm_peripheral_FF_TEST_SERVER_PARTITION_MMIO;
+extern struct platform_data_t tfm_peripheral_FF_TEST_DRIVER_PARTITION_MMIO;
+#define FF_TEST_UART_REGION           (&tfm_peripheral_FF_TEST_UART_REGION)
+#define FF_TEST_WATCHDOG_REGION       (&tfm_peripheral_FF_TEST_WATCHDOG_REGION)
+#define FF_TEST_NVMEM_REGION          (&tfm_peripheral_FF_TEST_NVMEM_REGION)
+#define FF_TEST_SERVER_PARTITION_MMIO (&tfm_peripheral_FF_TEST_SERVER_PARTITION_MMIO)
+#define FF_TEST_DRIVER_PARTITION_MMIO (&tfm_peripheral_FF_TEST_DRIVER_PARTITION_MMIO)
+#endif /* PSA_API_TEST_IPC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_PERIPHERALS_DEF_H__ */