nRF9151, NCS 3.4.0 AP-Protect re-enables itself after every reset despite CONFIG_NRF_APPROTECT_USE_UICR=y in app/mcuboot — TF-M never receives USE_UICR

I'm using nrf9151 and trying to upgrade from ncs3.2 to ncs 3.4. I have two builds, one with log disabled, other with rtt logging enabled. Both builds are working, but I can't use RTT anymore, because it makes flash erase when connecting (debug access disabled after flashing). I can't use UART for debugging, because all 4 instances are in use for other purposes. When I started this project, RTT worked ok. RTT started behave strangely somewhere from NCS3.0 (mass erase started, when disconnected and reconnected RTT), but now I can't use it at all.
I have been trying to resolve this with Claude and Nordic AI for days, but no positive result.

Here is summary:
On nRF9151 (NCS v3.4.0, sysbuild, TF-M enabled), debug access (RTT/SWD) works immediately after flashing, but is disabled again after every reset — even though:
`nrfutil device recover` is run before every flash
`SB_CONFIG_APPROTECT_USE_UICR=y` and `SB_CONFIG_SECURE_APPROTECT_USE_UICR=y` are set at sysbuild level
`CONFIG_NRF_APPROTECT_LOCK` / `CONFIG_NRF_SECURE_APPROTECT_LOCK` are confirmed not set in every domain
`nrfutil device protection-get --traits jlink` confirms:
Right after flashing: `Debug access is enabled (status value: None)`
After a reset: `Debug access is currently disabled (status value: All)`
Possible root cause found: Errata #36 (Access port gets locked in WFI/WFE)
While preparing this post I found nRF9151 Rev2 Errata #36, which matches my symptom almost exactly:
> Symptoms: The registers in the NRF_APPROTECT peripheral are not retained in SYSTEM ON IDLE mode.
> Conditions: The device enters SYSTEM ON IDLE mode after configuring access port protection to be open.
> Consequences: The access port is closed.
This would explain why debug access is open immediately after flashing (before the idle thread has run) but closes itself shortly after (once Zephyr's idle thread enters WFE/WFI for the first time) — independent of whatever is going on with the TF-M Kconfig forwarding described below.
I'm about to test the documented workaround (`NRF_POWER->TASKS_CONSTLAT = 1` at startup, guarded by `#ifdef DEBUG`) to see if it resolves the issue on its own, before assuming the TF-M/CMake forwarding gap below is actually the cause. Will update this post with results.
Final findings (after further isolation)
I was able to build the identical application against NCS v3.2.4 on the same physical board, which gave me a clean A/B comparison:
NCS 3.2.4: works. RTT debugging works reliably after flash and after reset, every time.
NCS 3.4.0: fails. Debug access is only open immediately after a flash+auto-reset cycle; it is lost on the next reset.
Ruled out so far:
Kconfig/CMakeCache is identical between the 3.2.4 (working) and 3.4.0 (failing) TF-M builds — `CONFIG_NRF_APPROTECT_LOCK/USER_HANDLING` = OFF and `NRF_APPROTECT`/`NRF_SECURE_APPROTECT` = OFF in both. So the earlier hypothesis about `CONFIG_NRF_APPROTECT_USE_UICR` not being forwarded to the nested TF-M ExternalProject (true, confirmed via `nrf/sysbuild/CMakeLists.txt`'s `${IMAGES}` loop not including the nested TF-M build) does not explain the 3.2 vs 3.4 difference, since the same gap exists in both.
`CONFIG_TFM_PROFILE_TYPE_MINIMAL=y` (present in the 3.4 project, absent in 3.2) is not the cause either — removing it in 3.4 just causes secure RAM overflow (140% of 32 KB) at link time, so the two projects aren't meaningfully different here (3.4 needs MINIMAL to fit in the same secure RAM budget; behavior with MINIMAL is unchanged).
New, very consistent observation distinguishing a "soft" reset from a real hardware reset on the 3.4.0 build:
Action Debug access App boots
Flash (auto-reset disabled) + reset issued via debugger/Programmer/VS Code (SWD-level reset, not power/pin) Stays enabled Does not start
Flash with auto-reset enabled (real hardware/pin reset) Becomes disabled immediately Starts and runs correctly
This suggests the full secure boot chain (MCUboot → TF-M secure init, including whatever APPROTECT/provisioning-related code executes there) only runs on a genuine hardware reset, and it is specifically that boot sequence which re-locks the access port — a debug-probe-issued soft reset neither fully re-boots the application nor re-locks APPROTECT. This points fairly specifically at TF-M's (or MCUboot's) secure platform init code executed during a real reset, and something in that code path changed between the TF-M revision bundled with NCS 3.2.4 and the one in NCS 3.4.0.
What I've verified so far (TF-M Kconfig forwarding investigation, kept for reference — not the root cause given the above)
1. All top-level sysbuild images have correct Kconfig:
`build/<app>/zephyr/.config`, `build/mcuboot/zephyr/.config`, and `build/zephyr/.config` (sysbuild) all show:
```
CONFIG_NRF_APPROTECT_USE_UICR=y
# CONFIG_NRF_APPROTECT_LOCK is not set
CONFIG_NRF_SECURE_APPROTECT_USE_UICR=y
# CONFIG_NRF_SECURE_APPROTECT_LOCK is not set
SB_CONFIG_APPROTECT_USE_UICR=y
SB_CONFIG_SECURE_APPROTECT_USE_UICR=y
```
2. TF-M's CMakeCache.txt is missing `USE_UICR` entirely, and its "master switch" defines are OFF:
`build/<app>/tfm/CMakeCache.txt`:
```
CONFIG_NRF_APPROTECT_LOCK:BOOL=OFF
CONFIG_NRF_APPROTECT_USER_HANDLING:BOOL=OFF
CONFIG_NRF_SECURE_APPROTECT_LOCK:BOOL=OFF
CONFIG_NRF_SECURE_APPROTECT_USER_HANDLING:BOOL=OFF
NRF_APPROTECT:BOOL=OFF
NRF_SECURE_APPROTECT:BOOL=OFF
```
No `CONFIG_NRF_APPROTECT_USE_UICR` line appears anywhere in TF-M's CMakeCache.txt.
3. Traced the mechanism in nrf sdk source:
`nrf/sysbuild/CMakeLists.txt` applies APPROTECT config only to sysbuild top-level `${IMAGES}`:
```cmake
if(SB_CONFIG_APPROTECT_USE_UICR)
set(normal_approtect CONFIG_NRF_APPROTECT_USE_UICR)
...
foreach(image ${IMAGES})
...
set_config_bool(${image} ${normal_approtect} y)
set_config_bool(${image} ${secure_approtect} y)
endforeach()
```
Since TF-M is built as a nested ExternalProject inside the `*_ns` application image (not a standalone sysbuild image), it is not included in `${IMAGES}`, so it never receives `CONFIG_NRF_APPROTECT_USE_UICR` / `CONFIG_NRF_SECURE_APPROTECT_USE_UICR`.
`nrf/modules/trusted-firmware-m/CMakeLists.txt` only forwards two of the four options to TF-M's own CMake config:
```cmake
$<$<BOOL:${CONFIG_NRF_APPROTECT_LOCK}>:-DCONFIG_NRF_APPROTECT_LOCK=ON>
$<$<BOOL:${CONFIG_NRF_APPROTECT_USER_HANDLING}>:-DCONFIG_NRF_APPROTECT_USER_HANDLING=ON>
$<$<BOOL:${CONFIG_NRF_SECURE_APPROTECT_LOCK}>:-DCONFIG_NRF_SECURE_APPROTECT_LOCK=ON>
$<$<BOOL:${CONFIG_NRF_SECURE_APPROTECT_USER_HANDLING}>:-DCONFIG_NRF_SECURE_APPROTECT_USER_HANDLING=ON>
```
`USE_UICR` (and `DISABLE`) are never forwarded to TF-M at all.
`nrf/modules/trusted-firmware-m/tfm_boards/CMakeLists.txt`:
```cmake
if(CONFIG_NRF_APPROTECT_LOCK)
target_compile_definitions(platform_s PUBLIC NRF_APPROTECT)
endif()
if(CONFIG_NRF_SECURE_APPROTECT_LOCK)
target_compile_definitions(platform_s PUBLIC NRF_SECURE_APPROTECT)
endif()
```
So the `NRF_APPROTECT` / `NRF_SECURE_APPROTECT` compile-time defines are only set when `LOCK` is enabled — which is expected in our case (we don't want LOCK). What I can't determine from CMake alone is what the TF-M platform init code (nRF91 `SystemInit`/`nrf91_handle_approtect()` equivalent inside `platform_s`) actually does when none of `LOCK`, `USER_HANDLING`, or `NRF_APPROTECT` compile-time defines are set — specifically, whether it still reads UICR->APPROTECT and applies it to CTRLAP, or whether it does nothing (leaving the SoC in its power-on-reset "secured" default).
Question
Is `CONFIG_NRF_APPROTECT_USE_UICR` (and `SECURE_` variant) supposed to reach TF-M's build at all in a sysbuild + TF-M project, or is TF-M expected to always default to reading UICR regardless of this Kconfig (i.e. is the missing forwarding intentional/harmless)?
If it IS supposed to reach TF-M, is there a correct way to force it — either via a sysbuild image-configuration hook, or a CMake overlay for the nested TF-M ExternalProject — rather than patching `nrf/modules/trusted-firmware-m/CMakeLists.txt` directly?
Is this related to the previously-known nRF91 APPROTECT issue (zephyrproject-rtos/zephyr#68850, fixed by #66858)? Environment here is already NCS 3.4.0 / Zephyr 4.4.0-ish, so I'd expect that fix to be present, but the symptom (works until reset, then locked again) looks very similar.
Environment
SoC: nRF9151 (nRF9151 DK)
NCS: v3.4.0
Toolchain: bundled NCS 3.4.0 toolchain
Build system: sysbuild, TF-M enabled (`*/ns` board target)
MCUboot + TF-M + application, no Partition Manager (fixed-partitions devicetree)
`nrfutil device recover` performed before every flash
Debugger: J-Link (onboard, DK)
Happy to provide full `.config`/`CMakeCache.txt` dumps or a minimal reproduction if useful.

Related