diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml
index 4d4598277cecb0c24478e292577fcb474a9c6a7b..486609030f98b550a323af5c56373fde466bf83c 100644
--- a/.github/workflows/doc-build.yml
+++ b/.github/workflows/doc-build.yml
@@ -47,7 +47,7 @@ jobs:
         pip3 install setuptools wheel
         pip3 install -r scripts/requirements-base.txt
         pip3 install -r scripts/requirements-doc.txt
-        pip3 install west==0.10.0a1
+        pip3 install west==0.10.1
 
     - name: west setup
       run: |
diff --git a/CODEOWNERS b/CODEOWNERS
index 0b13cbcbfd6d4c9fbb79e54602aaaa749bea9941..73996305e3853e4eb540145dd2bfe0c270231662 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -110,6 +110,7 @@
 /boards/arm/qemu_cortex_m*/               @ioannisg
 /boards/arm/quick_feather/                @kowalewskijan @kgugala
 /boards/arm/rak5010_nrf52840/             @gpaquet85
+/boards/arm/ronoth_lodev/                 @NorthernDean
 /boards/arm/xmc45_relax_kit/              @parthitce
 /boards/arm/sam4e_xpro/                   @nandojve
 /boards/arm/sam4l_ek/                     @nandojve
@@ -154,7 +155,6 @@
 /doc/guides/dts/                          @galak @mbolivar-nordic
 /doc/reference/bluetooth/                 @joerchan @jhedberg @Vudentz
 /doc/reference/devicetree/                @galak @mbolivar-nordic
-/doc/reference/resource_management/       @pabigot
 /doc/reference/networking/can*            @alexanderwachter
 /doc/security/                            @ceolin @d3zd3z
 /drivers/debug/                           @nashif
@@ -177,7 +177,6 @@
 /drivers/console/ipm_console.c            @finikorg
 /drivers/console/semihost_console.c       @luozhongyao
 /drivers/counter/counter_cmos.c           @dcpleung
-/drivers/counter/maxim_ds3231.c           @pabigot
 /drivers/crypto/*nrf_ecb*                 @maciekfabia @anangl
 /drivers/console/*mux*                    @jukkar
 /drivers/display/                         @vanwinkeljan
@@ -201,12 +200,10 @@
 /drivers/ethernet/*w5500*                 @parthitce
 /drivers/flash/                           @nashif @nvlsianpu
 /drivers/flash/*nrf*                      @nvlsianpu
-/drivers/flash/*spi_nor*                  @pabigot
-/drivers/gpio/                            @mnkp @pabigot
+/drivers/gpio/                            @mnkp
 /drivers/gpio/*ht16k33*                   @henrikbrixandersen
 /drivers/gpio/*lmp90xxx*                  @henrikbrixandersen
 /drivers/gpio/*stm32*                     @erwango
-/drivers/gpio/*sx1509b*                   @pabigot
 /drivers/gpio/*eos_s3*                    @wtatarski @kowalewskijan @kgugala
 /drivers/hwinfo/                          @alexanderwachter
 /drivers/i2s/i2s_ll_stm32*                @avisconti
@@ -253,7 +250,6 @@
 /drivers/pwm/*xlnx*                       @henrikbrixandersen
 /drivers/pwm/pwm_capture.c                @henrikbrixandersen
 /drivers/pwm/pwm_shell.c                  @henrikbrixandersen
-/drivers/regulator/                       @pabigot
 /drivers/sensor/                          @MaureenHelm
 /drivers/sensor/ams_iAQcore/              @alexanderwachter
 /drivers/sensor/ens210/                   @alexanderwachter
@@ -310,6 +306,7 @@
 /drivers/wifi/winc1500/                   @kludentwo
 /drivers/virtualization/		  @tbursztyka
 /dts/arc/                                 @abrodkin @ruuddw @iriszzw
+/dts/arm/acsip/                           @NorthernDean
 /dts/arm/atmel/sam4e*                     @nandojve
 /dts/arm/atmel/sam4l*                     @nandojve
 /dts/arm/atmel/samr21.dtsi                @benpicco
@@ -335,10 +332,12 @@
 /dts/arm/silabs/efm32gg11b*               @oanerer
 /dts/arm/silabs/efm32_jg_pg*              @chrta
 /dts/arm/silabs/efr32bg13p*               @mnkp
+/dts/arm/silabs/efr32xg13p*               @mnkp
 /dts/arm/silabs/efm32jg12b*               @chrta
 /dts/arm/silabs/efm32pg12b*               @chrta
 /dts/arm/silabs/efm32pg1b*                @rdmeneze
 /dts/arm/silabs/efr32mg21*                @l-alfred
+/dts/arm/silabs/efr32fg13*                @yonsch
 /dts/riscv/                               @kgugala @pgielda
 /dts/riscv/it8xxx2.dtsi                   @ite
 /dts/riscv/microsemi-miv.dtsi             @galak
@@ -432,7 +431,7 @@
 /include/dt-bindings/pcie/                @dcpleung
 /include/dt-bindings/usb/usb.h            @galak
 /include/emul.h                           @sjg20
-/include/fs/                              @nashif @nvlsianpu @de-nordic @pabigot
+/include/fs/                              @nashif @nvlsianpu @de-nordic
 /include/init.h                           @nashif @andyross
 /include/irq.h                            @dcpleung @nashif @andyross
 /include/irq_offload.h                    @dcpleung @nashif @andyross
@@ -449,7 +448,7 @@
 /include/net/lwm2m*.h                     @jukkar @rlubos
 /include/net/mqtt.h                       @jukkar @rlubos
 /include/posix/                           @pfalcon
-/include/power/power.h                    @pabigot @nashif @ceolin
+/include/power/power.h                    @nashif @ceolin
 /include/ptp_clock.h                      @jukkar
 /include/shared_irq.h                     @dcpleung @nashif @andyross
 /include/shell/                           @jakub-uC @nordic-krch
@@ -487,7 +486,6 @@
 /samples/drivers/display/                 @vanwinkeljan
 /samples/drivers/ht16k33/                 @henrikbrixandersen
 /samples/drivers/lora/                    @Mani-Sadhasivam
-/samples/drivers/counter/maxim_ds3231/    @pabigot
 /samples/subsys/lorawan/                  @Mani-Sadhasivam
 /samples/net/                             @jukkar @tbursztyka @pfalcon
 /samples/net/cloud/tagoio_http_post/      @nandojve
@@ -505,7 +503,7 @@
 /samples/subsys/mgmt/updatehub/           @nandojve @otavio
 /samples/subsys/mgmt/osdp/                @cbsiddharth
 /samples/subsys/usb/                      @jfischer-no
-/samples/subsys/power/                    @nashif @pabigot @ceolin
+/samples/subsys/power/                    @nashif @ceolin
 /samples/tfm_integration/                 @ioannisg @microbuilder
 /samples/userspace/                       @dcpleung @nashif
 /scripts/coccicheck                       @himanshujha199640 @JuliaLawall
@@ -515,7 +513,6 @@
 /scripts/pylib/twister/expr_parser.py     @nashif
 /scripts/schemas/twister/                 @nashif
 /scripts/gen_app_partitions.py            @dcpleung @nashif
-/scripts/gen_handles.py                   @pabigot
 /scripts/get_maintainer.py                @nashif
 /scripts/dts/                             @mbolivar-nordic @galak
 /scripts/release/                         @nashif
@@ -548,7 +545,7 @@
 /subsys/bluetooth/controller/             @carlescufi @cvinayak @thoh-ot @kruithofa
 /subsys/bluetooth/mesh/                   @jhedberg @trond-snekvik @joerchan @Vudentz
 /subsys/canbus/                           @alexanderwachter
-/subsys/cpp/                              @pabigot @vanwinkeljan
+/subsys/cpp/                              @vanwinkeljan
 /subsys/debug/                            @nashif
 /subsys/debug/coredump/                   @dcpleung
 /subsys/debug/gdbstub/                    @ceolin
@@ -566,7 +563,6 @@
 /subsys/fs/                               @nashif
 /subsys/fs/fcb/                           @nvlsianpu
 /subsys/fs/fuse_fs_access.c               @vanwinkeljan
-/subsys/fs/littlefs_fs.c                  @pabigot
 /subsys/fs/nvs/                           @Laczen
 /subsys/ipc/                              @ioannisg
 /subsys/logging/                          @nordic-krch
@@ -592,7 +588,7 @@
 /subsys/net/l2/                           @jukkar @tbursztyka
 /subsys/net/l2/canbus/                    @alexanderwachter @jukkar
 /subsys/net/*/openthread/                 @rlubos
-/subsys/power/                            @nashif @pabigot @ceolin
+/subsys/power/                            @nashif @ceolin
 /subsys/random/                           @dleach02
 /subsys/settings/                         @nvlsianpu
 /subsys/shell/                            @jakub-uC @nordic-krch
@@ -604,7 +600,6 @@
 /subsys/usb/                              @jfischer-no
 /subsys/usb/class/dfu/usb_dfu.c           @nvlsianpu
 /tests/                                   @nashif
-/tests/application_development/libcxx/    @pabigot
 /tests/arch/arm/                          @ioannisg @stephanosio
 /tests/benchmarks/cmsis_dsp/              @stephanosio
 /tests/boards/native_posix/               @aescolar @daor-oti
@@ -616,10 +611,9 @@
 /tests/crypto/mbedtls/                    @nashif @ceolin
 /tests/drivers/can/                       @alexanderwachter
 /tests/drivers/counter/                   @nordic-krch
-/tests/drivers/counter/maxim_ds3231_api/  @pabigot
 /tests/drivers/eeprom/                    @henrikbrixandersen @sjg20
 /tests/drivers/flash_simulator/           @nvlsianpu
-/tests/drivers/gpio/                      @mnkp @pabigot
+/tests/drivers/gpio/                      @mnkp
 /tests/drivers/hwinfo/                    @alexanderwachter
 /tests/drivers/spi/                       @tbursztyka
 /tests/drivers/uart/uart_async_api/       @Mierunski
@@ -635,7 +629,7 @@
 /tests/net/socket/socketpair/             @cfriedt
 /tests/net/socket/                        @jukkar @tbursztyka @pfalcon
 /tests/subsys/debug/coredump/             @dcpleung
-/tests/subsys/fs/                         @nashif @nvlsianpu @de-nordic @pabigot
+/tests/subsys/fs/                         @nashif @nvlsianpu @de-nordic
 /tests/subsys/settings/                   @nvlsianpu
 /tests/subsys/shell/                      @jakub-uC @nordic-krch
 # Get all docs reviewed
diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml
index d5c96cc9c114510095eeb839c200c13b60d7466b..bc7113293a22775375ed25ebaad8997f48106287 100644
--- a/MAINTAINERS.yml
+++ b/MAINTAINERS.yml
@@ -136,8 +136,11 @@ ARM arch:
         - MaureenHelm
         - stephanosio
     files:
-        - arch/arm/
-        - include/arch/arm/
+        - arch/arm/aarch32/
+        - arch/arm/common/
+        - arch/arm/offsets/
+        - include/arch/arm/aarch32
+        - include/arch/arm/*
         - tests/arch/arm/
     labels:
         - "area: ARM"
@@ -575,9 +578,7 @@ Documentation:
         - "area: HWINFO"
 
 "Drivers: I2C":
-    status: maintained
-    maintainers:
-        - pabigot
+    status: orphaned
     files:
         - drivers/i2c/
         - dts/bindings/i2c/
@@ -871,7 +872,6 @@ Filesystems:
         - de-nordic
         - Laczen
         - nashif
-        - pabigot
         - vanwinkeljan
     files:
         - include/fs/
@@ -910,7 +910,6 @@ Kernel:
         - nashif
         - ceolin
         - dcpleung
-        - pabigot
     files:
         - doc/reference/kernel/
         - include/kernel*.h
@@ -934,9 +933,7 @@ Base OS:
         - "area: Base OS"
 
 Little FS:
-    status: maintained
-    maintainers:
-        - pabigot
+    status: orphaned
     files:
         - subsys/fs/Kconfig.littlefs
         - subsys/fs/littlefs_fs.c
@@ -1141,7 +1138,6 @@ Power management:
         - ceolin
     collaborators:
         - nashif
-        - pabigot
         - mengxianglinx
     files:
         - include/power/power.h
@@ -1172,6 +1168,10 @@ Twister:
     collaborators:
         - chen-png
         - jocelyn-li
+        - galak
+        - PerMac
+        - enjiamai
+        - hakehuang
     files:
         - scripts/twister
         - scripts/pylib/twister/
@@ -1364,6 +1364,19 @@ STM32 Platforms:
         STM32 SOCs, dts files and related drivers. ST nucleo, disco and eval
         boards.
 
+Espressif Platforms:
+    status: maintained
+    maintainers:
+        - sylvioalves
+    files:
+        - drivers/*/*esp32*
+        - boards/xtensa/esp32/
+        - soc/xtensa/esp32/
+        - dts/xtensa/espressif/
+        - dts/bindings/*/*esp32*
+    labels:
+        - "platform: ESP32"
+
 Storage:
     status: maintained
     maintainers:
@@ -1463,6 +1476,7 @@ West:
     files:
         - scripts/west-commands.yml
         - scripts/west_commands/
+        - doc/guides/west/
     labels:
         - "area: West"
 
@@ -1496,6 +1510,9 @@ x86 arch:
         - arch/x86/
         - include/arch/x86/
         - tests/arch/x86/
+        - drivers/interrupt_controller/*intel*
+        - drivers/interrupt_controller/*ioapic*
+        - drivers/interrupt_controller/*loapic*
     labels:
         - "area: X86"
 
diff --git a/arch/arm/core/aarch32/vector_table.ld b/arch/arm/core/aarch32/vector_table.ld
index 256443fbf2c44cc35772adc0a169b61d5b2d6127..e379c49260196b0fb30e7692fa6cd796ab67adcd 100644
--- a/arch/arm/core/aarch32/vector_table.ld
+++ b/arch/arm/core/aarch32/vector_table.ld
@@ -38,7 +38,4 @@ KEEP(*(.vectors))
 
 _vector_end = .;
 
-KEEP(*(.openocd_dbg))
-KEEP(*(".openocd_dbg.*"))
-
 #include "cortex_m/vector_table_pad.ld"
diff --git a/arch/arm/core/aarch64/CMakeLists.txt b/arch/arm/core/aarch64/CMakeLists.txt
index c96f1e7b88c0b31398a5d52f1742e1ce119b2d2a..7bedf7a663dda7141f0959e126b0e86d58d19763 100644
--- a/arch/arm/core/aarch64/CMakeLists.txt
+++ b/arch/arm/core/aarch64/CMakeLists.txt
@@ -33,3 +33,5 @@ zephyr_library_sources_ifdef(CONFIG_CACHE_MANAGEMENT cache.c)
 if ((CONFIG_MP_NUM_CPUS GREATER 1) OR (CONFIG_SMP))
   zephyr_library_sources(smp.c)
 endif ()
+
+zephyr_cc_option_ifdef(CONFIG_USERSPACE -mno-outline-atomics)
diff --git a/arch/arm/core/aarch64/Kconfig b/arch/arm/core/aarch64/Kconfig
index 3127c5061aa557661bfbad33bc57895c4274834e..9fb2fd890b9b3ee7b90d1b6841f1dfae8a9242e6 100644
--- a/arch/arm/core/aarch64/Kconfig
+++ b/arch/arm/core/aarch64/Kconfig
@@ -67,6 +67,9 @@ config AARCH64_IMAGE_HEADER
 config PRIVILEGED_STACK_SIZE
 	default 4096
 
+config KOBJECT_TEXT_AREA
+	default 512 if TEST
+
 if CPU_CORTEX_A
 
 config ARMV8_A_NS
@@ -79,6 +82,7 @@ config ARMV8_A
 	bool
 	select ATOMIC_OPERATIONS_BUILTIN
 	select CPU_HAS_MMU
+	select ARCH_HAS_USERSPACE if ARM_MMU
 	help
 	  This option signifies the use of an ARMv8-A processor
 	  implementation.
@@ -129,6 +133,7 @@ config MMU_PAGE_SIZE
 
 config MAX_XLAT_TABLES
 	int "Maximum numbers of translation tables"
+	default 16 if USERSPACE
 	default 8
 	help
 	  This option specifies the maximum numbers of translation tables.
diff --git a/arch/arm/core/aarch64/mmu/CMakeLists.txt b/arch/arm/core/aarch64/mmu/CMakeLists.txt
index 5356b078bc3b9c7c330a5aa454b9c4fac22ae4da..72a75fafc283dd51530fd723313bdd28c39e8305 100644
--- a/arch/arm/core/aarch64/mmu/CMakeLists.txt
+++ b/arch/arm/core/aarch64/mmu/CMakeLists.txt
@@ -2,4 +2,4 @@
 
 zephyr_library()
 
-zephyr_library_sources(arm_mmu.c)
+zephyr_library_sources(arm_mmu.c low_level.S)
diff --git a/arch/arm/core/aarch64/mmu/arm_mmu.c b/arch/arm/core/aarch64/mmu/arm_mmu.c
index 36f30f8525ce6cd7c1159e3a31231cb8d8e136fe..a02cdd4ca8f95db8a3eb228c450cf905d9a39bc5 100644
--- a/arch/arm/core/aarch64/mmu/arm_mmu.c
+++ b/arch/arm/core/aarch64/mmu/arm_mmu.c
@@ -10,6 +10,7 @@
 #include <device.h>
 #include <init.h>
 #include <kernel.h>
+#include <kernel_arch_func.h>
 #include <kernel_arch_interface.h>
 #include <kernel_internal.h>
 #include <logging/log.h>
@@ -631,13 +632,13 @@ static const struct arm_mmu_flat_range mmu_zephyr_ranges[] = {
 	{ .name  = "zephyr_code",
 	  .start = _image_text_start,
 	  .end   = _image_text_end,
-	  .attrs = MT_NORMAL | MT_P_RX_U_NA | MT_DEFAULT_SECURE_STATE },
+	  .attrs = MT_NORMAL | MT_P_RX_U_RX | MT_DEFAULT_SECURE_STATE },
 
 	/* Mark rodata segment cacheable, read only and execute-never */
 	{ .name  = "zephyr_rodata",
 	  .start = _image_rodata_start,
 	  .end   = _image_rodata_end,
-	  .attrs = MT_NORMAL | MT_P_RO_U_NA | MT_DEFAULT_SECURE_STATE },
+	  .attrs = MT_NORMAL | MT_P_RO_U_RO | MT_DEFAULT_SECURE_STATE },
 };
 
 static inline void add_arm_mmu_flat_range(struct arm_mmu_ptables *ptables,
@@ -917,20 +918,6 @@ int arch_mem_domain_init(struct k_mem_domain *domain)
 	return 0;
 }
 
-void arch_mem_domain_destroy(struct k_mem_domain *domain)
-{
-	struct arm_mmu_ptables *domain_ptables = &domain->arch.ptables;
-	k_spinlock_key_t key;
-
-	MMU_DEBUG("%s\n", __func__);
-
-	sys_slist_remove(&domain_list, NULL, &domain->arch.node);
-	key = k_spin_lock(&xlat_lock);
-	discard_table(domain_ptables->base_xlat_table, BASE_XLAT_LEVEL);
-	domain_ptables->base_xlat_table = NULL;
-	k_spin_unlock(&xlat_lock, key);
-}
-
 static void private_map(struct arm_mmu_ptables *ptables, const char *name,
 			uintptr_t phys, uintptr_t virt, size_t size, uint32_t attrs)
 {
@@ -1002,6 +989,16 @@ void arch_mem_domain_thread_add(struct k_thread *thread)
 	}
 
 	thread->arch.ptables = domain_ptables;
+	if (thread == _current) {
+		if (!is_ptable_active(domain_ptables)) {
+			z_arm64_swap_ptables(thread);
+		}
+	} else {
+#ifdef CONFIG_SMP
+		/* the thread could be running on another CPU right now */
+		arch_sched_ipi();
+#endif
+	}
 
 	if (is_migration) {
 		reset_map(old_ptables, __func__, thread->stack_info.start,
@@ -1029,4 +1026,28 @@ void arch_mem_domain_thread_remove(struct k_thread *thread)
 		  thread->stack_info.size);
 }
 
+void z_arm64_swap_ptables(struct k_thread *incoming)
+{
+	struct arm_mmu_ptables *ptables = incoming->arch.ptables;
+
+	if (!is_ptable_active(ptables)) {
+		z_arm64_set_ttbr0((uintptr_t)ptables->base_xlat_table);
+	}
+}
+
+void z_arm64_thread_pt_init(struct k_thread *incoming)
+{
+	struct arm_mmu_ptables *ptables;
+
+	if ((incoming->base.user_options & K_USER) == 0)
+		return;
+
+	ptables = incoming->arch.ptables;
+
+	/* Map the thread stack */
+	map_thread_stack(incoming, ptables);
+
+	z_arm64_swap_ptables(incoming);
+}
+
 #endif /* CONFIG_USERSPACE */
diff --git a/arch/arm/core/aarch64/mmu/low_level.S b/arch/arm/core/aarch64/mmu/low_level.S
new file mode 100644
index 0000000000000000000000000000000000000000..583f61447d5925cd4d09a4c94d86682ea838b5ac
--- /dev/null
+++ b/arch/arm/core/aarch64/mmu/low_level.S
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <toolchain.h>
+#include <linker/sections.h>
+#include <arch/cpu.h>
+
+_ASM_FILE_PROLOGUE
+
+/*
+ * Switch TTBR0
+ */
+
+GTEXT(z_arm64_set_ttbr0)
+SECTION_FUNC(TEXT, z_arm64_set_ttbr0)
+
+	/* Disable all the caches */
+	mrs	x2, sctlr_el1
+	mov_imm	x1, (SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+	and	x1, x2, x1
+	msr	sctlr_el1, x1
+	isb
+
+	/* Invalidate the TLBs */
+	tlbi	vmalle1
+	dsb	sy
+	isb
+
+	/* Switch the TTBR0 */
+	msr	ttbr0_el1, x0
+	isb
+
+	/* Restore the saved SCTLR_EL1 */
+	msr	sctlr_el1, x2
+	isb
+
+	ret
diff --git a/arch/arm/core/aarch64/smp.c b/arch/arm/core/aarch64/smp.c
index 8f1e055be4a908bda7a5230db92f9a4919e2e53d..3edb3a9a85a9d21adeba4dac460c611ec065c6b6 100644
--- a/arch/arm/core/aarch64/smp.c
+++ b/arch/arm/core/aarch64/smp.c
@@ -119,6 +119,14 @@ void sched_ipi_handler(const void *unused)
 {
 	ARG_UNUSED(unused);
 
+#ifdef CONFIG_USERSPACE
+	/*
+	 * Make sure a domain switch by another CPU is effective on this CPU.
+	 * This is a no-op if the page table is already the right one.
+	 */
+	z_arm64_swap_ptables(_current);
+#endif
+
 	z_sched_ipi();
 }
 
diff --git a/arch/arm/core/aarch64/switch.S b/arch/arm/core/aarch64/switch.S
index 846516bf720b14a47f69390293815e4383061963..8c695595c725c9bdc40f1a78a4789ef791be71ea 100644
--- a/arch/arm/core/aarch64/switch.S
+++ b/arch/arm/core/aarch64/switch.S
@@ -76,6 +76,12 @@ SECTION_FUNC(TEXT, z_arm64_context_switch)
 
 	mov	sp, x1
 
+#ifdef CONFIG_USERSPACE
+	stp     xzr, x30, [sp, #-16]!
+	bl      z_arm64_swap_ptables
+	ldp     xzr, x30, [sp], #16
+#endif
+
 #ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING
 	stp	xzr, x30, [sp, #-16]!
 	bl	z_thread_mark_switched_in
diff --git a/arch/arm/core/aarch64/thread.c b/arch/arm/core/aarch64/thread.c
index 66b3863fa613f716c3afaf7e81ef8292f64a2f05..ab2ab3c7db627a7ec1efe473456389c0f9711a28 100644
--- a/arch/arm/core/aarch64/thread.c
+++ b/arch/arm/core/aarch64/thread.c
@@ -83,6 +83,9 @@ FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry,
 	z_arch_esf_t *pInitCtx;
 	uintptr_t stack_ptr;
 
+	/* Map the thread stack */
+	z_arm64_thread_pt_init(_current);
+
 	/* Setup the private stack */
 	_current->arch.priv_stack_start = (uint64_t)(_current->stack_obj);
 
diff --git a/arch/arm/core/aarch64/vector_table.S b/arch/arm/core/aarch64/vector_table.S
index ec5e8959321b706399c1a35e504151a5476748a6..e7db015cf08fe539480fae17f35d12c379680c2f 100644
--- a/arch/arm/core/aarch64/vector_table.S
+++ b/arch/arm/core/aarch64/vector_table.S
@@ -157,11 +157,17 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
 
 	/* Lower EL using AArch64 / Synchronous */
 	.align 7
-	b	.
+	z_arm64_enter_exc x0, x1
+	b	z_arm64_sync_exc
 
 	/* Lower EL using AArch64 / IRQ */
 	.align 7
-	b	.
+	z_arm64_enter_exc x0, x1
+#ifdef CONFIG_GEN_SW_ISR_TABLE
+	b 	_isr_wrapper
+#else
+	b	z_irq_spurious
+#endif
 
 	/* Lower EL using AArch64 / FIQ */
 	.align 7
@@ -169,7 +175,8 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
 
 	/* Lower EL using AArch64 / SError */
 	.align 7
-	b	.
+	z_arm64_enter_exc x0, x1
+	b	z_arm64_serror
 
 	/* Lower EL using AArch32 / Synchronous */
 	.align 7
diff --git a/arch/arm/include/aarch64/kernel_arch_func.h b/arch/arm/include/aarch64/kernel_arch_func.h
index d80b51df0b32fd516064bed79bc8b8eb154211c4..fc06999a0ac5fc67a238470c32d587a0678884c1 100644
--- a/arch/arm/include/aarch64/kernel_arch_func.h
+++ b/arch/arm/include/aarch64/kernel_arch_func.h
@@ -41,6 +41,7 @@ static inline void arch_switch(void *switch_to, void **switched_from)
 
 extern void z_arm64_fatal_error(z_arch_esf_t *esf, unsigned int reason);
 extern void z_arm64_userspace_enter(z_arch_esf_t *esf);
+extern void z_arm64_set_ttbr0(uintptr_t ttbr0);
 
 #endif /* _ASMLANGUAGE */
 
diff --git a/arch/riscv/core/pmp/core_pmp.c b/arch/riscv/core/pmp/core_pmp.c
index 387ed22af90c52b69d60d893b31695a5c73ba0a5..762e65e5df166efcff094c599f0a05e1b215f50e 100644
--- a/arch/riscv/core/pmp/core_pmp.c
+++ b/arch/riscv/core/pmp/core_pmp.c
@@ -503,18 +503,6 @@ void arch_mem_domain_thread_add(struct k_thread *thread)
 	}
 }
 
-void arch_mem_domain_destroy(struct k_mem_domain *domain)
-{
-	sys_dnode_t *node, *next_node;
-	struct k_thread *thread;
-
-	SYS_DLIST_FOR_EACH_NODE_SAFE(&domain->mem_domain_q, node, next_node) {
-		thread = CONTAINER_OF(node, struct k_thread, mem_domain_info);
-
-		arch_mem_domain_thread_remove(thread);
-	}
-}
-
 void arch_mem_domain_partition_add(struct k_mem_domain *domain,
 				    uint32_t partition_id)
 {
diff --git a/arch/x86/core/x86_mmu.c b/arch/x86/core/x86_mmu.c
index 8d85ee0e9b9e428722423be0890a6592922895b1..dd1d0c7bf0d0144d4b3be8bcec4e840c10033806 100644
--- a/arch/x86/core/x86_mmu.c
+++ b/arch/x86/core/x86_mmu.c
@@ -1389,11 +1389,6 @@ void arch_mem_domain_thread_add(struct k_thread *thread)
 void arch_mem_domain_thread_remove(struct k_thread *thread)
 {
 
-}
-
-void arch_mem_domain_destroy(struct k_mem_domain *domain)
-{
-
 }
 #else
 /* Memory domains each have a set of page tables assigned to them */
@@ -1621,11 +1616,6 @@ void arch_mem_domain_partition_remove(struct k_mem_domain *domain,
 		     partition->size);
 }
 
-void arch_mem_domain_destroy(struct k_mem_domain *domain)
-{
-	/* No-op, this is eventually getting removed in 2.5 */
-}
-
 /* Called on thread exit or when moving it to a different memory domain */
 void arch_mem_domain_thread_remove(struct k_thread *thread)
 {
diff --git a/boards/arm/efr32_radio/Kconfig.board b/boards/arm/efr32_radio/Kconfig.board
index d3675dcd40fad19fcff7e8c1e337366a889e0236..c493455d55444af967e1a1991d111c0bc7997bc1 100644
--- a/boards/arm/efr32_radio/Kconfig.board
+++ b/boards/arm/efr32_radio/Kconfig.board
@@ -1,4 +1,5 @@
-# EFR32BG13 BRD4104A / EFR32MG21 BRD4180A board
+# EFR32BG13 BRD4104A / EFR32MG21 BRD4180A /
+# EFR32FG1P BRD4250B / EFR32FG13P BRD4255A board
 
 # Copyright (c) 2020 Piotr Mienkowski
 # Copyright (c) 2020 TriaGnoSys GmbH
@@ -21,3 +22,9 @@ config BOARD_EFR32_RADIO_BRD4180A
 	depends on SOC_SERIES_EFR32MG21
 	select BOARD_EFR32_RADIO
 	select SOC_PART_NUMBER_EFR32MG21A020F1024IM32
+
+config BOARD_EFR32_RADIO_BRD4255A
+	bool "Silicon Labs BRD4255A (Flex Gecko Radio Board)"
+	depends on SOC_SERIES_EFR32FG13P
+	select BOARD_EFR32_RADIO
+	select SOC_PART_NUMBER_EFR32FG13P233F512GM48
diff --git a/boards/arm/efr32_radio/Kconfig.defconfig b/boards/arm/efr32_radio/Kconfig.defconfig
index 9d7184e99123789bafa49f59a50f0acca37b2ada..12ab81157c159354c427b3230349ff56622dbaa5 100644
--- a/boards/arm/efr32_radio/Kconfig.defconfig
+++ b/boards/arm/efr32_radio/Kconfig.defconfig
@@ -10,6 +10,7 @@ config BOARD
 	default "efr32_radio_brd4104a" if BOARD_EFR32_RADIO_BRD4104A
 	default "efr32_radio_brd4250b" if BOARD_EFR32_RADIO_BRD4250B
 	default "efr32_radio_brd4180a" if BOARD_EFR32_RADIO_BRD4180A
+	default "efr32_radio_brd4255a" if BOARD_EFR32_RADIO_BRD4255A
 
 config CMU_HFXO_FREQ
 	default 38400000
diff --git a/boards/arm/efr32_radio/board.cmake b/boards/arm/efr32_radio/board.cmake
index a18647742ece9f337a429c1ef2471d48e8f4ca22..4c5100906c084ec735bc671b48aecdda3ea84bb0 100644
--- a/boards/arm/efr32_radio/board.cmake
+++ b/boards/arm/efr32_radio/board.cmake
@@ -8,6 +8,8 @@ elseif(CONFIG_BOARD_EFR32_RADIO_BRD4250B)
 board_runner_args(jlink "--device=EFR32FG1PxxxF256")
 elseif(CONFIG_BOARD_EFR32_RADIO_BRD4180A)
 board_runner_args(jlink "--device=EFR32MG21AxxxF1024")
+elseif(CONFIG_BOARD_EFR32_RADIO_BRD4255A)
+board_runner_args(jlink "--device=EFR32FG13PxxxF512")
 endif()
 
 include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
diff --git a/boards/arm/efr32_radio/doc/brd4255a.rst b/boards/arm/efr32_radio/doc/brd4255a.rst
new file mode 100644
index 0000000000000000000000000000000000000000..7dd82025047c6bea3ac36f24a04e1bef345bb53e
--- /dev/null
+++ b/boards/arm/efr32_radio/doc/brd4255a.rst
@@ -0,0 +1,113 @@
+.. _efr32_radio_brd4255a:
+
+EFR32 BRD4255A (SLWRB4255A)
+###########################
+
+Overview
+********
+
+The EFR32FG13P Flex Gecko 2.4 GHz and 915 MHz Radio Board is delivered as a
+`standalone Proprietary Wireless radio board`_. It contains a EFR32FG13P Wireless
+SoC built on an ARM Cortex®-M4F processor with excellent low power capabilities.
+
+.. figure:: ./efr32fg13-slwrb4255a.jpg
+   :height: 262px
+   :align: center
+   :alt: SLWRB4255A Flex Gecko 2.4 GHz and 915 MHz Radio Board
+
+   SLWRB4255A (image courtesy of Silicon Labs)
+
+The BRD4255A a.k.a. SLWRB4255A radio board plugs into the Wireless Starter Kit
+Mainboard BRD4001A and is supported as one of :ref:`efr32_radio`.
+
+Hardware
+********
+
+- EFR32FG13P233F512GM48 Flex Gecko SoC
+- CPU core: ARM Cortex®-M4 with FPU
+- Flash memory: 512 kB
+- RAM: 64 kB
+- Transmit power: up to 19 dBm
+- Operation frequency: 2.4 GHz, 915 MHz
+- Crystals for LFXO (32.768 kHz) and HFXO (38.4 MHz).
+
+For more information about the EFR32FG13 SoC and BRD4255A board, refer to these
+documents:
+
+- `EFR32FG13 Website`_
+- `EFR32FG13 Datasheet`_
+- `EFR32xG13 Reference Manual`_
+- `BRD4255A Reference Manual`_
+
+Supported Features
+==================
+
+Please refer to
+:ref:`EFR32 Radio Board Supported Features <efr32_radio_supported_features>`
+for details of the configuration and common features supported by the
+efr32_radio_brd4255a board.
+
+The default configuration can be found in the defconfig file:
+
+	``boards/arm/efr32_radio/efr32_radio_brd4255a_defconfig``
+
+System Clock
+============
+
+The EFR32FG13P SoC is configured to use the 38.4 MHz external oscillator on the
+board.
+
+Serial Port
+===========
+
+The EFR32FG13P SoC has three USARTs and one Low Energy UARTs (LEUART).
+USART0 is connected to the board controller and is used for the console.
+
+Programming and Debugging
+*************************
+
+Please refer to
+:ref:`Programming and Debugging EFR32 Radio Board <efr32_radio_programming>`
+for details on the supported debug interfaces.
+
+Flashing
+========
+
+Connect the BRD4001A board with a mounted BRD4255A radio module to your host
+computer using the USB port.
+
+Here is an example for the :ref:`hello_world` application.
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/hello_world
+   :board: efr32_radio_brd4255a
+   :goals: flash
+
+Open a serial terminal (minicom, putty, etc.) with the following settings:
+
+- Speed: 115200
+- Data: 8 bits
+- Parity: None
+- Stop bits: 1
+
+Reset the board and you should see the following message in the terminal:
+
+.. code-block:: console
+
+   Hello World! efr32_radio_brd4255a
+
+
+.. _EFR32FG13 Website:
+   https://www.silabs.com/wireless/proprietary/efr32fg13-series-1-sub-ghz-2-4-ghz-socs
+
+.. _EFR32FG13 Datasheet:
+   https://www.silabs.com/documents/public/data-sheets/efr32fg13-datasheet.pdf
+
+.. _EFR32xG13 Reference Manual:
+   https://www.silabs.com/documents/public/reference-manuals/efr32xg13-rm.pdf
+
+.. _standalone Proprietary Wireless radio board:
+   https://www.silabs.com/development-tools/wireless/proprietary/slwrb4255a-efr32fg13-915-mhz-radio-board
+
+.. _BRD4255A Reference Manual:
+   https://www.silabs.com/documents/public/reference-manuals/brd4255a-rm.pdf
diff --git a/boards/arm/efr32_radio/doc/efr32fg13-slwrb4255a.jpg b/boards/arm/efr32_radio/doc/efr32fg13-slwrb4255a.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5d50e488732e95f5106947114281309de9060ff1
Binary files /dev/null and b/boards/arm/efr32_radio/doc/efr32fg13-slwrb4255a.jpg differ
diff --git a/boards/arm/efr32_radio/doc/index.rst b/boards/arm/efr32_radio/doc/index.rst
index 2aae6df2c175dcf5e59aee7e73603d7d10b243b7..8ce9fdcd00cf1953c1144c444119c02d3588b8d3 100644
--- a/boards/arm/efr32_radio/doc/index.rst
+++ b/boards/arm/efr32_radio/doc/index.rst
@@ -9,6 +9,7 @@ EFR32 Radio Boards
    brd4104a.rst
    brd4250b.rst
    brd4180a.rst
+   brd4255a.rst
 
 Overview
 ********
diff --git a/boards/arm/efr32_radio/efr32_radio_brd4255a.dts b/boards/arm/efr32_radio/efr32_radio_brd4255a.dts
new file mode 100644
index 0000000000000000000000000000000000000000..9971387653c95b4f4db9c8989a9890a0f638e988
--- /dev/null
+++ b/boards/arm/efr32_radio/efr32_radio_brd4255a.dts
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Piotr Mienkowski
+ * Copyright (c) 2021 Yonatan Schachter
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/dts-v1/;
+#include <silabs/efr32fg13p233f512gm48.dtsi>
+#include "efr32_radio.dtsi"
+
+/ {
+	model = "Silicon Labs BRD4255A (Flex Gecko Radio Board)";
+	compatible = "silabs,efr32_radio_brd4255a", "silabs,efr32fg13p";
+};
+
+&cpu0 {
+	clock-frequency = <38400000>;
+};
+
+&flash0 {
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		/* Reserve 32 kB for the bootloader */
+		boot_partition: partition@0 {
+			label = "mcuboot";
+			reg = <0x0 0x00008000>;
+			read-only;
+		};
+
+		/* Reserve 220 kB for the application in slot 0 */
+		slot0_partition: partition@8000 {
+			label = "image-0";
+			reg = <0x0008000 0x00037000>;
+		};
+
+		/* Reserve 220 kB for the application in slot 1 */
+		slot1_partition: partition@3f000 {
+			label = "image-1";
+			reg = <0x0003f000 0x00037000>;
+		};
+
+		/* Reserve 32 kB for the scratch partition */
+		scratch_partition: partition@76000 {
+			label = "image-scratch";
+			reg = <0x00076000 0x00008000>;
+		};
+
+		/* Set 8Kb of storage at the end of the 512KB of flash */
+		storage_partition: partition@7e000 {
+			label = "storage";
+			reg = <0x0007e000 0x00002000>;
+		};
+
+	};
+};
diff --git a/boards/arm/efr32_radio/efr32_radio_brd4255a.yaml b/boards/arm/efr32_radio/efr32_radio_brd4255a.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..34923d504c5b1089aa6ca31eb2c5208c36865feb
--- /dev/null
+++ b/boards/arm/efr32_radio/efr32_radio_brd4255a.yaml
@@ -0,0 +1,21 @@
+identifier: efr32_radio_brd4255a
+name: BRD4255A
+type: mcu
+arch: arm
+ram: 64
+flash: 512
+toolchain:
+  - zephyr
+  - gnuarmemb
+  - xtools
+supported:
+  - counter
+  - gpio
+  - nvs
+  - spi
+  - uart
+  - watchdog
+testing:
+  ignore_tags:
+    - net
+    - bluetooth
diff --git a/boards/arm/efr32_radio/efr32_radio_brd4255a_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4255a_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..53e6ecbdc976e16ae87ae24944dec865e20d1dce
--- /dev/null
+++ b/boards/arm/efr32_radio/efr32_radio_brd4255a_defconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: Apache-2.0
+
+CONFIG_SOC_SERIES_EFR32FG13P=y
+CONFIG_BOARD_EFR32_RADIO_BRD4255A=y
+CONFIG_ARM_MPU=y
+CONFIG_CONSOLE=y
+CONFIG_UART_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_CORTEX_M_SYSTICK=y
+CONFIG_GPIO=y
+CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000
+CONFIG_CMU_HFCLK_HFXO=y
+CONFIG_SOC_GECKO_EMU_DCDC=y
+CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y
diff --git a/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb_defconfig b/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb_defconfig
index 3cc7f5bc2db7a51432eebc20ab4fdc64595d017c..00d352f331dd7dd55b3c7e37ce6a115e795fa7e4 100644
--- a/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb_defconfig
+++ b/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb_defconfig
@@ -23,9 +23,6 @@ CONFIG_CLOCK_NPCX_APB1_PRESCALER=6
 CONFIG_CLOCK_NPCX_APB2_PRESCALER=6
 CONFIG_CLOCK_NPCX_APB3_PRESCALER=6
 
-# Pinmux Driver
-CONFIG_PINMUX=y
-
 # UART Driver
 CONFIG_SERIAL=y
 CONFIG_UART_INTERRUPT_DRIVEN=y
diff --git a/boards/arm/nucleo_f767zi/doc/index.rst b/boards/arm/nucleo_f767zi/doc/index.rst
index 561812622a97d055df13b0d7eab6b5022be3cb3d..5275c68ca7a7a5d6037cae7d15d7d659cc62933f 100644
--- a/boards/arm/nucleo_f767zi/doc/index.rst
+++ b/boards/arm/nucleo_f767zi/doc/index.rst
@@ -122,6 +122,9 @@ features:
 +-----------+------------+-------------------------------------+
 | RNG       | on-chip    | True Random number generator        |
 +-----------+------------+-------------------------------------+
+| DAC       | on-chip    | DAC Controller                      |
++-----------+------------+-------------------------------------+
+
 
 (*) nucleo_f767zi with soc cut-A (Device marking A) has some ethernet
     instability (https://github.com/zephyrproject-rtos/zephyr/issues/26519).
diff --git a/boards/arm/nucleo_f767zi/nucleo_f767zi.dts b/boards/arm/nucleo_f767zi/nucleo_f767zi.dts
index 54cf17deac993015a41e119b1d202f76267bb764..635603c4d3c9ad45a32f7c978706adf70cf0f328 100644
--- a/boards/arm/nucleo_f767zi/nucleo_f767zi.dts
+++ b/boards/arm/nucleo_f767zi/nucleo_f767zi.dts
@@ -135,6 +135,11 @@
 	status = "okay";
 };
 
+&dac1 {
+	status = "okay";
+	pinctrl-0 = <&dac_out1_pa4>;
+};
+
 &rng {
 	status = "okay";
 };
diff --git a/boards/arm/nucleo_f767zi/nucleo_f767zi.yaml b/boards/arm/nucleo_f767zi/nucleo_f767zi.yaml
index ca3646d32851988090f0a1512ab2637c835151e0..847654163fff7cc5cf6211a714f070bd45ffa081 100644
--- a/boards/arm/nucleo_f767zi/nucleo_f767zi.yaml
+++ b/boards/arm/nucleo_f767zi/nucleo_f767zi.yaml
@@ -23,3 +23,4 @@ supported:
   - watchdog
   - counter
   - can
+  - dac
diff --git a/boards/arm/nucleo_l552ze_q/CMakeLists.txt b/boards/arm/nucleo_l552ze_q/CMakeLists.txt
index 83a4f7ea62a6cfca80e3ceb9eae7b5909bfc21ca..16db9aa1ea3a64ec477c222572494f2698236235 100644
--- a/boards/arm/nucleo_l552ze_q/CMakeLists.txt
+++ b/boards/arm/nucleo_l552ze_q/CMakeLists.txt
@@ -11,58 +11,8 @@ elseif(${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "gnuarmemb")
 endif()
 
 if (CONFIG_BUILD_WITH_TFM)
-	# Set default image versions if not defined elsewhere
-	if (NOT DEFINED TFM_IMAGE_VERSION_S)
-		set(TFM_IMAGE_VERSION_S 0.0.0+0)
-	endif()
-
-	if (NOT DEFINED TFM_IMAGE_VERSION_NS)
-		set(TFM_IMAGE_VERSION_NS 0.0.0+0)
-	endif()
-
-	set(PREPROCESSED_FILE_S "${CMAKE_BINARY_DIR}/tfm/bl2/ext/mcuboot/CMakeFiles/signing_layout_s.dir/signing_layout_s.o")
-	set(PREPROCESSED_FILE_NS "${CMAKE_BINARY_DIR}/tfm/bl2/ext/mcuboot/CMakeFiles/signing_layout_ns.dir/signing_layout_ns.o")
-	set(TFM_MCUBOOT_DIR "${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/trusted-firmware-m/bl2/ext/mcuboot")
-
-	# Configure which format (full or hash) to include the public key in
-	# the image manifest
-	set(TFM_PUBLIC_KEY_FORMAT "full")
-
-	#Create and sign for concatenated binary image, should align with the TF-M BL2
-	set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
-
-		#Sign secure binary image with public key
-		COMMAND ${PYTHON_EXECUTABLE} ${TFM_MCUBOOT_DIR}/scripts/wrapper/wrapper.py
-			 --layout ${PREPROCESSED_FILE_S}
-			 -k ${CONFIG_TFM_KEY_FILE_S}
-			 --public-key-format ${TFM_PUBLIC_KEY_FORMAT}
-			 --align 1
-			 -v ${TFM_IMAGE_VERSION_S}
-			 --pad
-			 --pad-header
-			 ${ADD_NS_IMAGE_MIN_VER}
-			 -s auto
-			 -H 0x400
-			 $<TARGET_PROPERTY:tfm,TFM_S_BIN_FILE>
-			 ${CMAKE_BINARY_DIR}/tfm_s_signed.bin
-
-		#Sign non-secure binary image with public key
-		COMMAND ${PYTHON_EXECUTABLE} ${TFM_MCUBOOT_DIR}/scripts/wrapper/wrapper.py
-			 --layout ${PREPROCESSED_FILE_NS}
-			 -k ${CONFIG_TFM_KEY_FILE_NS}
-			 --public-key-format ${TFM_PUBLIC_KEY_FORMAT}
-			 --align 1
-			 -v ${TFM_IMAGE_VERSION_NS}
-			 -s auto
-			 ${ADD_S_IMAGE_MIN_VER}
-			 -H 0x400
-			 ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_BIN_NAME}
-			 ${CMAKE_BINARY_DIR}/zephyr_ns_signed.bin
-
-		#Copy mcuboot.bin
-		COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:tfm,BL2_BIN_FILE> ${CMAKE_BINARY_DIR}/mcuboot.bin
-
+	set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts
 		#Execute post build script postbuild.sh
 		COMMAND ${CMAKE_BINARY_DIR}/tfm/postbuild.sh ${COMPILER_FULL_PATH}
-      )
+	)
 endif()
diff --git a/boards/arm/nucleo_l552ze_q/board.cmake b/boards/arm/nucleo_l552ze_q/board.cmake
index c963eb224fe6a76ffbc88f28f2d520b17b88f877..c1f04ce1bc6e4521d358d28108ad71938bfb6f2a 100644
--- a/boards/arm/nucleo_l552ze_q/board.cmake
+++ b/boards/arm/nucleo_l552ze_q/board.cmake
@@ -1,5 +1,15 @@
- set_ifndef(BOARD_DEBUG_RUNNER pyocd)
- set_ifndef(BOARD_FLASH_RUNNER pyocd)
+if(CONFIG_BUILD_WITH_TFM)
+  set(FLASH_BASE_ADDRESS_S 0x0C000000)
+
+  if (CONFIG_HAS_FLASH_LOAD_OFFSET)
+    MATH(EXPR TFM_HEX_BASE_ADDRESS_NS "${FLASH_BASE_ADDRESS_S}+${CONFIG_FLASH_LOAD_OFFSET}")
+  else()
+    set(TFM_HEX_BASE_ADDRESS_NS ${TFM_FLASH_BASE_ADDRESS_S})
+  endif()
+endif()
+
+set_ifndef(BOARD_DEBUG_RUNNER pyocd)
+set_ifndef(BOARD_FLASH_RUNNER pyocd)
 
 board_runner_args(pyocd "--target=stm32l552zetxq")
 
diff --git a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst
index 561126992afc69fd3e6eadd76aa57076a6d84f9b..fc6bb3d491d99d37089fae16d5b4c0a112d5d20d 100644
--- a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst
+++ b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst
@@ -276,7 +276,16 @@ You should see the following message on the console:
 Building a secure/non-secure with Arm |reg| TrustZone |reg|
 -----------------------------------------------------------
 
-The TF-M integration sample :ref:`tfm_ipc` can be run by a Nucleo L552ZE Q, using the ``nucleo_l552ze_q_ns`` target. When building a ``*_ns`` image with TF-M, a ``build/tfm/install/postbuild.sh`` bash script will be run as a post-build step to make some required flash layout changes. The ``build/tfm/install/postbuild.sh`` script will also be used to flash the board. Check the ``build/tfm/install`` directory to ensure that the commands required by these scripts (``readlink``, etc.) are available on your system.
+The TF-M integration sample :ref:`tfm_ipc` can be run by a Nucleo L552ZE Q,
+using the ``nucleo_l552ze_q_ns`` target. When building a ``*_ns`` image with TF-M,
+a ``build/tfm/install/postbuild.sh`` bash script will be run as a post-build step
+to make some required flash layout changes. The ``build/tfm/regression.sh`` script
+will need to be run to perform device initialization, and then run ``west flash --hex-file build/tfm_merged.hex``
+to flash the board.
+
+Check the ``build/tfm/`` directory to ensure that the commands required by these scripts
+(``readlink``, etc.) are available on your system. Please also check ``STM32_Programmer_CLI``
+used for initialization is available in the PATH.
 
 Debugging
 =========
diff --git a/boards/arm/ronoth_lodev/Kconfig.board b/boards/arm/ronoth_lodev/Kconfig.board
new file mode 100644
index 0000000000000000000000000000000000000000..c0135583575c4bf33eb9226295bda668290d6ce2
--- /dev/null
+++ b/boards/arm/ronoth_lodev/Kconfig.board
@@ -0,0 +1,7 @@
+# Ronoth LoDev board configuration
+# Copyright (c) 2020/2021 Dean Weiten <dmw@weiten.com>
+# SPDX-License-Identifier: Apache-2.0
+
+config BOARD_RONOTH_LODEV
+	bool "Ronoth LoDev"
+	depends on SOC_STM32L073XX
diff --git a/boards/arm/ronoth_lodev/Kconfig.defconfig b/boards/arm/ronoth_lodev/Kconfig.defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..5e3a44a811e8ae44cce810cfbbc04ff5c8e8fa9f
--- /dev/null
+++ b/boards/arm/ronoth_lodev/Kconfig.defconfig
@@ -0,0 +1,14 @@
+# Ronoth LoDev board configuration
+# Copyright (c) 2020/2021 Dean Weiten <dmw@weiten.com>
+# SPDX-License-Identifier: Apache-2.0
+
+if BOARD_RONOTH_LODEV
+
+config BOARD
+	default "ronoth_lodev"
+
+config SPI_STM32_INTERRUPT
+	default y
+	depends on SPI
+
+endif # BOARD_RONOTH_LODEV
diff --git a/boards/arm/ronoth_lodev/board.cmake b/boards/arm/ronoth_lodev/board.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..678e864b82141970a9c26d81af57f48ecb24346c
--- /dev/null
+++ b/boards/arm/ronoth_lodev/board.cmake
@@ -0,0 +1,8 @@
+# Ronoth LoDev board configuration
+# Copyright (c) 2020/2021 Dean Weiten <dmw@weiten.com>
+# SPDX-License-Identifier: Apache-2.0
+
+board_runner_args(jlink "--device=STM32L073RZ" "--speed=4000")
+
+include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
+include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
diff --git a/boards/arm/ronoth_lodev/doc/img/acsip_s76s.png b/boards/arm/ronoth_lodev/doc/img/acsip_s76s.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2f6af822fab74c20a0dc08cbbffd8ee75a8293c
Binary files /dev/null and b/boards/arm/ronoth_lodev/doc/img/acsip_s76s.png differ
diff --git a/boards/arm/ronoth_lodev/doc/img/lodev.png b/boards/arm/ronoth_lodev/doc/img/lodev.png
new file mode 100644
index 0000000000000000000000000000000000000000..9096909f3dfb8f38d2e55bff01fa4f75f6674333
Binary files /dev/null and b/boards/arm/ronoth_lodev/doc/img/lodev.png differ
diff --git a/boards/arm/ronoth_lodev/doc/img/pinout.png b/boards/arm/ronoth_lodev/doc/img/pinout.png
new file mode 100644
index 0000000000000000000000000000000000000000..58ccd3da6855b4bf8185633446e7ed744a9548c8
Binary files /dev/null and b/boards/arm/ronoth_lodev/doc/img/pinout.png differ
diff --git a/boards/arm/ronoth_lodev/doc/index.rst b/boards/arm/ronoth_lodev/doc/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..4ca8165ec9ba1ffa672ee1786f066db23a5becf2
--- /dev/null
+++ b/boards/arm/ronoth_lodev/doc/index.rst
@@ -0,0 +1,181 @@
+.. _ronoth_lodev:
+
+Ronoth LoDev
+############
+
+========
+Overview
+========
+
+The Ronoth_ LoDev_ is a small open source board containing a `AcSIP S76S`_  SiP from AcSIP_.
+The `full LoDev design details`_ are available on on GitHub.  The LoDev_ board can be purchased
+from Ronoth_ or from CrowdSupply_.
+
+The S76S contains an `STMicro STM32L073RZ`_ MCU, a `Semtech SX1276`_ LoRaWAN transceiver,
+and a +20 dBm power amplifier.  Refer to `AcSIP S76S Product Information Brief`_ for details.
+
+Zephyr applications may use the **ronoth_lodev** configuration to run on this board.
+
+.. figure:: img/lodev.png
+     :width: 291px
+     :align: center
+     :height: 217px
+     :alt: Image of Ronoth LoDev open source development board containing S76S system on a chip
+
+     Ronoth LoDev
+
+`Board design files`_ are available on GitHub.
+
+================
+Device Resources
+================
+
+The embedded `STMicro STM32L073RZ`_ has some GPIOs and SPI2 internally committed to the LoRaWAN
+transceiver operation.  See `internally dedicated ports`_ for a list of resources committed to this function.
+
+=========
+Debugging
+=========
+
+Programming and debugging uses the SWD port, as on any STM32 processor.  An ST-LINK/V2 adapter
+may be used with the appropriate software (*st-utils* package on Linux).
+
+=================
+Connector Pin-Out
+=================
+
+The LoDev has two rows of headers.  Pin 1 on both connectors is closest to the micro-USB connector on the board,
+furthest from the RF (antenna) connector.
+
+When viewed from the top (component) side of the board, with the micro-USB connector closest and RF (antenna)
+connector furthest away, the CN6_ connector is on the left, the CN7_ connector is on the right.
+
+UART1 on the S76S SiP is connected to a USB-to-UART device connected to the micro USB connector, so generally
+PA9 and PA10 are unavailable for I/Os.
+
+A helpful silkscreen legend is provided on the board.
+
+.. figure:: img/pinout.png
+     :width: 600px
+     :align: center
+     :alt: Ronoth LoDev sketch with pinout
+
+     Ronth LoDev Pinout
+
+.. _CN6:
+
+-----------
+CN6 Pin-Out
+-----------
+
+=== ======== ======================================================
+Pin Function Note
+=== ======== ======================================================
+1   3.3V     Output 500 mA max
+2   GND
+3   PC1
+4   PC0
+5   PB8
+6   BOOT0
+7   PB7
+8   PB6
+9   PB5
+10  PD2
+11  PC12
+12  PC11
+13  PC10
+14  PA14     SWCLK
+15  PA13     SWDIO
+16  PA12
+17  PA11
+18  PA9      USB serial Tx drives this pin (input) for UART1
+19  PA10     USB serial Rx is driven by this pin (output) for UART1
+20  PA8
+=== ======== ======================================================
+
+.. _CN7:
+
+-----------
+CN7 Pin-Out
+-----------
+
+=== ======== ============================
+Pin Function Note
+=== ======== ============================
+1   PC2
+2   PC3
+3   nRESET
+4   PA0
+5   PA2
+6   PA3
+7   PA4
+8   PA5
+9   PA6
+10  PA7
+11  PC4
+12  PC5
+13  PB0
+14  PB1
+15  PC6
+16  PC7
+17  PC8
+18  PC9
+19  GND
+20  PA1      Used in S76S as “RF FEM CPS”
+=== ======== ============================
+
+.. _internally dedicated ports:
+
+--------------------------
+Internally Dedicated Ports
+--------------------------
+
+======== ======== ============= ==== =========================
+Pin name Pin Type I/O Structure Note Function
+======== ======== ============= ==== =========================
+PA15     I/O      FT            -    INTERNAL SX1276 D5
+PB3      I/O      FTf           -    INTERNAL SX1276 D4
+PB4      I/O      FTf           -    INTERNAL SX1276 D3
+PB9      I/O      FTf           -    INTERNAL SX1276 D2
+PB10     I/O      FT            -    INTERNAL SX1276 Reset
+PB11     I/O      FT            -    INTERNAL SX1276 D0
+PB12     I/O      FT            -    INTERNAL SX1276 SPI nCS
+PB13     I/O      FTf           -    INTERNAL SX1276 SPI2_SCK
+PB14     I/O      FTf           -    INTERNAL SX1276 SPI2_MISO
+PB15     I/O      FT            -    INTERNAL SX1276 SPI2_MOSI
+PC13     I/O      FT            -    INTERNAL SX1276 D1
+======== ======== ============= ==== =========================
+
+==========
+References
+==========
+
+.. _Ronoth: https://ronoth.com/
+
+.. _LoDev: https://ronoth.com/products/lodev-s76s-lora-soc-development-board?variant=31608819417220
+
+.. _AcSIP: http://www.acsip.com.tw
+
+.. _AcSIP S76S: http://www.acsip.com.tw/index.php?action=products-detail&fid1=11&fid2=29&fid3=27&id=79&lang=3
+
+.. _AcSIP S76S Product Information Brief: http://www.acsip.com.tw/upload/product_attach/S76S_Brief_ver02.pdf
+
+.. _CrowdSupply: https://www.crowdsupply.com/ronoth/lodev
+
+.. _full LoDev design details: https://github.com/ronoth/LoDev
+
+.. _Board design files: https://github.com/ronoth/LoDev
+
+.. _posted on MBed by Steve Osborn: https://os.mbed.com/users/steve918/
+
+.. _STMicro STM32L073RZ: STMicro STM32L073RZ
+
+.. _Semtech SX1276: https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1276
+
+=======
+License
+=======
+
+This document Copyright (c) 2021 Dean Weiten <dmw@weiten.com>
+
+SPDX-License-Identifier: Apache-2.0
diff --git a/boards/arm/ronoth_lodev/doc/s76s.rst b/boards/arm/ronoth_lodev/doc/s76s.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f731242bedcf491dc5977e53786819b0b3de82f7
--- /dev/null
+++ b/boards/arm/ronoth_lodev/doc/s76s.rst
@@ -0,0 +1,256 @@
+.. _acsip_s76s:
+
+AcSIP S76S
+##########
+
+========
+Overview
+========
+
+The `AcSIP S76S`_  is an SiP from AcSIP_ containing an `STMicro STM32L073RZ`_ MCU,
+a `Semtech SX1276`_ LoRaWAN transceiver, and a +20 dBm power amplifier.  Refer to the
+`AcSIP S76S Product Information Brief`_ for details.  Further information is available
+from the `AcSIP Product Data Download`_ site (may need login). The parts are `available through TechShip`_.
+
+Zephyr applications may use the **acsip_s76s** configuration to use this SiP.
+
+.. figure:: img/acsip_s76s.png
+     :width: 189px
+     :align: center
+     :height: 115px
+     :alt: AcSIP S76S system on a chip, containing STMicro STM32L073RZ and Semtech SX1276
+
+     AcSIP S76S
+
+================
+Device Resources
+================
+
+The embedded `STMicro STM32L073RZ`_ has some GPIOs and SPI2 internally committed to the LoRaWAN
+transceiver operation.  See `internally committed table`_ for a list of resources committed to this function.
+
+As a result, some functions, ports and features of the `STMicro STM32L073RZ`_ are not available.
+See `unavailable table`_ for a list of resources not available due to a lack of pin-out.
+
+Available pinned-out resources are listed in `this table`_.  The actual `S76S pinout table`_ is below.
+
+These tables are STM32L07x generic - some pinned-out resources may be unavailable due to limitations
+on the `STMicro STM32L073RZ`_ processor itself.  Consult with the `STMicro STM32L073RZ`_ documentation.
+
+===========
+Development
+===========
+
+The Ronoth_ LoDev_ board is an open source development board, see its board description files.
+
+=========
+Debugging
+=========
+
+Programming and debugging uses the SWD port, as on any STM32 processor.  An ST-LINK/V2 adapter
+may be used with the appropriate software (*st-utils* package on Linux).
+
+.. _S76S pinout table:
+
+==================================
+Pin Assignments and Available Pins
+==================================
+
+-------------------
+S76S Pin Assignment
+-------------------
+
+=== ================ === ================
+Pin Function         Pin Function
+=== ================ === ================
+1   NC               32  GND
+2   GND              33  RF_ANT
+3   GND              34  GND
+4   PC1              35  GND
+5   PC2              36  PA1\_RF\_FEM_CPS
+6   PC3              37  GND
+7   NC               38  NC
+8   NC               39  GND
+9   NC               40  NC
+10  NC               41  GND
+11  NC               42  NC
+12  nReset           43  VDD
+13  PA0              44  VDD
+14  GND              45  PA8\_USART1\_CK
+15  GND              46  PA10\_USART1\_RX
+16  PA2\_TxD\_A      47  PA9\_USART1\_TX
+17  PA3\_RxD\_A      48  PA11\_USART1\_CTS
+18  PA4\_SPI1\_NSS   49  PA12\_USART1\_RTS
+19  PA5\_SPI1\_SCK   50  PA13_SWDIO
+20  PA6\_SPI1\_MISO  51  PA14_SWCLK
+21  PA7\_SPI1\_MOSI  52  PC10
+22  PC4              53  PC11
+23  PC5              54  PC12
+24  PB0\_IO\_INT1    55  PD2
+25  PB1\_IO\_INT2    56  PB5
+26  PC6              57  PB6_SCL
+27  PC7              58  PB7_SDA
+28  PC8              59  BOOT0
+29  PC9              60  PB8\_IO\_LED_FCT
+30  RXTX/RFMOD       61  GND
+31  GND              62  GND
+=== ================ === ================
+
+.. _this table:
+
+--------------------------------
+Ports Connected to External Pins
+--------------------------------
+
+======== ======== ============= ==== ========================================================================================================== =======================================
+Pin name Pin Type I/O Structure Note Alternate functions                                                                                        Additional functions
+======== ======== ============= ==== ========================================================================================================== =======================================
+BOOT0    I                      -    -                                                                                                          -
+NRST     I/O      -             -    -                                                                                                          -
+PA0      I/O      TC            -    TIM2_CH1, TSC_G1_IO1, USART2_CTS, TIM2_ETR, USART4_TX, COMP1_OUT                                           COMP1_INM, ADC_IN0, RTC_TAMP2/WKUP1
+PA1      I/O      FT            -    EVENTOUT, LCD_SEG0, TIM2_CH2, TSC_G1_IO2, USART2_RTS/USART2_DE, TIM21_ETR, USART4_RX                       COMP1_INP, ADC_IN1
+PA2      I/O      FT            -    TIM21_CH1, LCD_SEG1, TIM2_CH3, TSC_G1_IO3, USART2_TX, LPUART1_TX, COMP2_OUT                                COMP2_INM, ADC_IN2
+PA3      I/O      FT            -    TIM21_CH2, LCD_SEG2, TIM2_CH4, TSC_G1_IO4, USART2_RX, LPUART1_RX                                           COMP2_INP, ADC_IN3
+PA4      I/O      TC            (1)  SPI1_NSS, TSC_G2_IO1, USART2_CK, TIM22_ETR                                                                 COMP1_INM, COMP2_INM, ADC_IN4, DAC_OUT1
+PA5      I/O      TC            -    SPI1_SCK, TIM2_ETR, TSC_G2_IO2, TIM2_CH1                                                                   COMP1_INM, COMP2_INM, ADC_IN5, DAC_OUT2
+PA6      I/O      FT            -    SPI1_MISO, LCD_SEG3, TIM3_CH1, TSC_G2_IO3, LPUART1_CTS, TIM22_CH1, EVENTOUT, COMP1_OUT                     ADC_IN6
+PA7      I/O      FT            -    SPI1_MOSI, LCD_SEG4, TIM3_CH2, TSC_G2_IO4, TIM22_CH2, EVENTOUT, COMP2_OUT                                  ADC_IN7
+PA8      I/O      FTf           -    MCO, LCD_COM0, USB_CRS_SYNC, EVENTOUT, USART1_CK, I2C3_SCL                                                 -
+PA9      I/O      FTf           -    MCO, LCD_COM1, TSC_G4_IO1, USART1_TX, I2C1_SCL, I2C3_SMBA                                                  -
+PA10     I/O      FTf           -    LCD_COM2, TSC_G4_IO2, USART1_RX, I2C1_SDA                                                                  -
+PA11     I/O      FT            (2)  SPI1_MISO, EVENTOUT, TSC_G4_IO3, USART1_CTS, COMP1_OUT                                                     USB_DM
+PA12     I/O      FT            (2)  SPI1_MOSI, EVENTOUT, TSC_G4_IO4, USART1_RTS/USART1_DE, COMP2_OUT                                           USB_DP
+PA13     I/O      FT            -    SWDIO, USB_NOE, LPUART1_RX                                                                                 -
+PA14     I/O      FT            -    SWCLK, USART2_TX, LPUART1_TX                                                                               -
+PB0      I/O      FT            -    EVENTOUT, LCD_SEG5, TIM3_CH3, TSC_G3_IO2                                                                   LCD_VLCD3, ADC_IN8, VREF_OUT
+PB1      I/O      FT            -    LCD_SEG6, TIM3_CH4, TSC_G3_IO3, LPUART1_RTS/LPUART1_DE                                                     ADC_IN9, VREF_OUT
+PB5      I/O      FT            -    SPI1_MOSI, LCD_SEG9, LPTIM1_IN1, I2C1_SMBA, TIM3_CH2/TIM22_CH2, USART1_CK, USART5_CK, USART5_RTS/USART5_DE COMP2_INP
+PB6      I/O      FTf           -    USART1_TX, I2C1_SCL, LPTIM1_ETR, TSC_G5_IO3                                                                COMP2_INP
+PB7      I/O      FTf           -    USART1_RX, I2C1_SDA, LPTIM1_IN2, TSC_G5_IO4, USART4_CTS                                                    COMP2_INP, PVD_IN
+PB8      I/O      FTf           -    LCD_SEG16, TSC_SYNC, I2C1_SCL                                                                              -
+PC1      I/O      FTf           -    LPTIM1_OUT, LCD_SEG19, EVENTOUT, TSC_G7_IO2, LPUART1_TX, I2C3_SDA                                          ADC_IN11
+PC2      I/O      FTf           -    LPTIM1_IN2, LCD_SEG20, SPI2_MISO/I2S2_MCK, TSC_G7_IO3                                                      ADC_IN12
+PC3      I/O      FT            -    LPTIM1_ETR, LCD_SEG21, SPI2_MOSI/I2S2_SD, TSC_G7_IO4                                                       ADC_IN13
+PC4      I/O      FT            -    EVENTOUT, LCD_SEG22, LPUART1_TX                                                                            ADC_IN14
+PC5      I/O      FT            -    LCD_SEG23, LPUART1_RX, TSC_G3_IO1                                                                          ADC_IN15
+PC6      I/O      FT            -    TIM22_CH1, LCD_SEG24, TIM3_CH1, TSC_G8_IO1                                                                 -
+PC7      I/O      FT            -    TIM22_CH2, LCD_SEG25, TIM3_CH2, TSC_G8_IO2                                                                 -
+PC8      I/O      FT            -    TIM22_ETR, LCD_SEG26, TIM3_CH3, TSC_G8_IO3                                                                 -
+PC9      I/O      FTf           -    TIM21_ETR, LCD_SEG27, USB_NOE/TIM3_CH4, TSC_G8_IO4, I2C3_SDA                                               -
+PC10     I/O      FT            -    LPUART1_TX, LCD_COM4/LCD_SEG2 8/LCD_SEG48, USART4_TX                                                       -
+PC11     I/O      FT            -    LPUART1_RX, LCD_COM5/LCD_SEG2 9/LCD_SEG49, USART4_RX                                                       -
+PC12     I/O      FT            -    LCD_COM6/LCD_SEG3 0/LCD_SEG50, USART5_TX, USART4_CK                                                        -
+PD2      I/O      FT            -    LPUART1_RTS/LPUART1_DE, LCD_COM7/LCD_SEG3 1/LCD_SEG51, TIM3_ETR, USART5_RX                                 -
+======== ======== ============= ==== ========================================================================================================== =======================================
+
+Notes:
+
+1. PA4 offers a reduced touch sensing sensitivity. It is thus recommended to use it as sampling capacitor I/O.
+2. These pins are powered by VDD_USB. For all characteristics that refer to VDD, VDD_USB must be used instead.
+
+.. _internally committed table:
+
+--------------------------
+Internally Dedicated Ports
+--------------------------
+
+======== ======== ============= ==== =========================
+Pin name Pin Type I/O Structure Note Function
+======== ======== ============= ==== =========================
+PA15     I/O      FT            -    INTERNAL SX1276 D5
+PB3      I/O      FTf           -    INTERNAL SX1276 D4
+PB4      I/O      FTf           -    INTERNAL SX1276 D3
+PB9      I/O      FTf           -    INTERNAL SX1276 D2
+PB10     I/O      FT            -    INTERNAL SX1276 Reset
+PB11     I/O      FT            -    INTERNAL SX1276 D0
+PB12     I/O      FT            -    INTERNAL SX1276 SPI nCS
+PB13     I/O      FTf           -    INTERNAL SX1276 SPI2_SCK
+PB14     I/O      FTf           -    INTERNAL SX1276 SPI2_MISO
+PB15     I/O      FT            -    INTERNAL SX1276 SPI2_MOSI
+PC13     I/O      FT            -    INTERNAL SX1276 D1
+======== ======== ============= ==== =========================
+
+.. _unavailable table:
+
+-----------------------------------
+Ports Not Available / Not Connected
+-----------------------------------
+
+====================== ======== ============= ==== ================================================================= ====================
+Pin name               Pin Type I/O Structure Note Alternate functions                                               Additional functions
+====================== ======== ============= ==== ================================================================= ====================
+PC0                    I/O      FTf           -    LPTIM1_IN1, LCD_SEG18, EVENTOUT, TSC_G7_IO1, LPUART1_RX, I2C3_SCL ADC_IN10
+PC14- OSC32_IN (PC14)  I/O      FT            -    -                                                                 OSC32_IN
+PC15- OSC32_OUT (PC15) I/O      TC            -    -                                                                 OSC32_OUT
+PD0                    I/O      FT            -    TIM21_CH1, SPI2_NSS/I2S2_WS                                       -
+PD1                    I/O      FT            -    SPI2_SCK/I2S2_CK                                                  -
+PD3                    I/O      FT            -    USART2_CTS, LCD_SEG44, SPI2_MISO/I2S2_MCK                         -
+PD4                    I/O      FT            -    USART2_RTS/USART2_DE, SPI2_MOSI/I2S2_SD                           -
+PD5                    I/O      FT            -    USART2_TX                                                         -
+PD6                    I/O      FT            -    USART2_RX                                                         -
+PD7                    I/O      FT            -    USART2_CK, TIM21_CH2                                              -
+PD8                    I/O      FT            -    LPUART1_TX, LCD_SEG28                                             -
+PD9                    I/O      FT            -    LPUART1_RX, LCD_SEG29                                             -
+PD10                   I/O      FT            -    LCD_SEG30                                                         -
+PD11                   I/O      FT            -    LPUART1_CTS, LCD_SEG31                                            -
+PD12                   I/O      FT            -    LPUART1_RTS/LPUART1_DE, LCD_SEG32                                 -
+PD13                   I/O      FT            -    LCD_SEG33                                                         -
+PD14                   I/O      FT            -    LCD_SEG34                                                         -
+PD15                   I/O      FT            -    USB_CRS_SYNC, LCD_SEG35                                           -
+PE0                    I/O      FT            -    LCD_SEG36, EVENTOUT                                               -
+PE1                    I/O      FT            -    LCD_SEG37, EVENTOUT                                               -
+PE2                    I/O      FT            -    LCD_SEG38, TIM3_ETR                                               -
+PE3                    I/O      FT            -    TIM22_CH1, LCD_SEG39, TIM3_CH1                                    -
+PE4                    I/O      FT            -    TIM22_CH2, TIM3_CH2                                               -
+PE5                    I/O      FT            -    TIM21_CH1, TIM3_CH3                                               -
+PE6                    I/O      FT            -    TIM21_CH2, TIM3_CH4                                               RTC_TAMP3/WKUP3
+PE7                    I/O      FT            -    LCD_SEG45, USART5_CK/USART5_RTS/USART5_DE                         -
+PE8                    I/O      FT            -    LCD_SEG46, USART4_TX                                              -
+PE9                    I/O      FT            -    TIM2_CH1, LCD_SEG47, TIM2_ETR, USART4_RX                          -
+PE10                   I/O      FT            -    TIM2_CH2, LCD_SEG40, USART5_TX                                    -
+PE11                   I/O      FT            -    TIM2_CH3, USART5_RX                                               LCD_VLCD1
+PE12                   I/O      FT            -    TIM2_CH4, SPI1_NSS                                                LCD_VLCD3
+PE13                   I/O      FT            -    LCD_SEG41, SPI1_SCK                                               -
+PE14                   I/O      FT            -    LCD_SEG42, SPI1_MISO                                              -
+PE15                   I/O      FT            -    LCD_SEG43, SPI1_MOSI                                              -
+PH0-OSC_IN (PH0)       I/O      TC            -    USB_CRS_SYNC                                                      OSC_IN
+PH1- OSC_OUT (PH1)     I/O      TC            -    -                                                                 OSC_OUT
+PH9                    I/O      FT            -    -                                                                 -
+PH10                   I/O      FT            -    -                                                                 -
+VDD_USB                S                      -    -                                                                 -
+VDDA                   S        -             -    -                                                                 -
+VLCD                   S                      -    -
+VREF-                  S        -             -    -                                                                 -
+VREF+                  S        -             -    -                                                                 -
+VSSA                   S        -             -    -                                                                 -
+====================== ======== ============= ==== ================================================================= ====================
+
+==========
+References
+==========
+
+.. _AcSIP: http://www.acsip.com.tw
+
+.. _AcSIP S76S: http://www.acsip.com.tw/index.php?action=products-detail&fid1=11&fid2=29&fid3=27&id=79&lang=3
+
+.. _AcSIP S76S Product Information Brief: http://www.acsip.com.tw/upload/product_attach/S76S_Brief_ver02.pdf
+
+.. _AcSIP Product Data Download: http://www.acsip.com.tw/index.php?action=technical
+
+.. _available through TechShip: https://techship.com/products/acsip-lorawan-module-s76s/
+
+.. _Ronoth: https://ronoth.com/
+
+.. _LoDev: https://ronoth.com/products/lodev-s76s-lora-soc-development-board?variant=31608819417220
+
+.. _STMicro STM32L073RZ: STMicro STM32L073RZ
+
+.. _Semtech SX1276: https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1276
+
+=======
+License
+=======
+
+This document Copyright (c) 2021 Dean Weiten <dmw@weiten.com>
+
+SPDX-License-Identifier: Apache-2.0
diff --git a/boards/arm/ronoth_lodev/ronoth_lodev.dts b/boards/arm/ronoth_lodev/ronoth_lodev.dts
new file mode 100644
index 0000000000000000000000000000000000000000..3df7d161d7c9c1e0d91e990663916056400465d5
--- /dev/null
+++ b/boards/arm/ronoth_lodev/ronoth_lodev.dts
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c)  2020/2021 Dean Weiten <dmw@weiten.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * Note: SPI2 and several GPIOs are not available in the S76S - these are connected
+ * to the in-package Semtech SX1276 LoRa transceiver.  See the documentation for details.
+ */
+
+/dts-v1/;
+#include <acsip/s76s.dtsi>
+
+/ {
+	model = "Ronoth LoDev";
+	compatible = "ronoth,lodev";
+
+	chosen {
+		zephyr,console = &usart1;
+		zephyr,shell-uart = &usart1;
+		zephyr,sram = &sram0;
+		zephyr,flash = &flash0;
+	};
+
+	/*
+	 * On Ronoth LoDev and perhaps other boards,
+	 * Red LED on PA5.
+	 */
+	leds {
+		compatible = "gpio-leds";
+		red_led_0: led_0 {
+			gpios = <&gpioa 5 GPIO_ACTIVE_HIGH>;
+			label = "User LD2";
+		};
+	};
+
+	/* Arbitrarily use PC9 as a button input. */
+	gpio_keys {
+		compatible = "gpio-keys";
+		user_button: button {
+			label = "User";
+			gpios = <&gpioc 9 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	cn6_header: lodev_connector_1 {
+		compatible = "lodev_cn6";
+		#gpio-cells = <2>;
+		gpio-map-mask = <0xffffffff 0xffffffc0>;
+		gpio-map-pass-thru = <0 0x3f>;
+		gpio-map =	/*	<0 0 -      - 0>,		 3.3V */
+		/*	<1 0 -      - 0>,		 GND */
+			<2 0 &gpioc 1 0>,		/* PC1 */
+			<3 0 &gpioc 0 0>,		/* PC0 */
+			<4 0 &gpiob 8 0>,		/* PB8 */
+		/*	<5 0 -      - 0>,		 BOOT0 */
+			<6 0 &gpiob 7 0>,		/* PB7 */
+			<7 0 &gpiob 6 0>,		/* PB6 */
+			<8 0 &gpiob 5 0>,		/* PB5 */
+			<9 0 &gpiod 2 0>,		/* PD2 */
+			<10 0 &gpioc 12 0>,		/* PC12 */
+			<11 0 &gpioc 11 0>,		/* PC11 */
+			<12 0 &gpioc 10 0>,		/* PC10 */
+			<13 0 &gpioa 14 0>,		/* PA14 / SWCLK */
+			<14 0 &gpioa 13 0>,		/* PA13 / SWDIO */
+			<15 0 &gpioa 12 0>,		/* PA12 */
+			<16 0 &gpioa 11 0>,		/* PA11 */
+			<17 0 &gpioa 9 0>,		/* PA9 (UART1 Rx connected to USB) */
+			<18 0 &gpioa 10 0>,		/* PA10 (UART1 Tx connected to USB) */
+			<19 0 &gpioa 8 0>;		/* PA8 */
+	};
+
+	cn7_header: lodev_connector_2 {
+		compatible = "lodev_cn7";
+		#gpio-cells = <2>;
+		gpio-map-mask = <0xffffffff 0xffffffc0>;
+		gpio-map-pass-thru = <0 0x3f>;
+		gpio-map =		<0 0 &gpioc 2 0>,		/* PC2 */
+			<1 0 &gpioc 3 0>,		/* PC3 */
+		/*	<2 0 -      - 0>,		 nRESET */
+			<3 0 &gpioa 0 0>,		/* PA0 */
+			<4 0 &gpioa 2 0>,		/* PA2 */
+			<4 0 &gpioa 3 0>,		/* PA3 */
+			<6 0 &gpioa 4 0>,		/* PA4 */
+			<7 0 &gpioa 5 0>,		/* PA5 - connected to red LED1 */
+			<8 0 &gpioa 6 0>,		/* PA6 */
+			<9 0 &gpioa 7 0>,		/* PA7 */
+			<10 0 &gpioc 4 0>,		/* PC4 */
+			<11 0 &gpioc 5 0>,		/* PC5 */
+			<12 0 &gpiob 0 0>,		/* PB0 */
+			<13 0 &gpiob 1 0>,		/* PB1 */
+			<14 0 &gpioc 6 0>,		/* PC6 */
+			<15 0 &gpioc 7 0>,		/* PC7 */
+			<16 0 &gpioc 8 0>,		/* PC8 */
+			<17 0 &gpioc 9 0>,		/* PC9 */
+		/*	<18 0 -      - 0>,		 GND */
+			<19 0 &gpioa 1 0>;		/* PA1 (also used in S76S as "RF FEM CPS" */
+	};
+
+	aliases {
+		led0 = &red_led_0;
+		sw0 = &user_button;
+		eeprom-0 = &eeprom;
+		lora0 = &lora;
+	};
+};
+
+&usart1 {
+	pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>;
+	current-speed = <115200>;
+	status = "okay";
+};
+
+&usart2 {
+	pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3>;
+	current-speed = <115200>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>;
+	clock-frequency = <I2C_BITRATE_FAST>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_nss_pa4 &spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>;
+	status = "okay";
+};
+
+
+&iwdg {
+	status = "okay";
+};
+
+&adc1 {
+	pinctrl-0 = <&adc_in0_pa0>;
+	status = "okay";
+};
+
+&dac1 {
+	status = "okay";
+	pinctrl-0 = <&dac_out1_pa4>;
+};
+
+&rtc {
+	status = "okay";
+};
+
+&rng {
+	status = "okay";
+};
+
+&eeprom {
+	status = "okay";
+};
diff --git a/boards/arm/ronoth_lodev/ronoth_lodev.yaml b/boards/arm/ronoth_lodev/ronoth_lodev.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..73b28f9aa71bc49dadcd646a15c2e62ab3a14be9
--- /dev/null
+++ b/boards/arm/ronoth_lodev/ronoth_lodev.yaml
@@ -0,0 +1,17 @@
+identifier: ronoth_lodev
+name: Ronoth LoDev
+type: mcu
+arch: arm
+toolchain:
+  - zephyr
+  - gnuarmemb
+  - xtools
+ram: 20
+flash: 192
+supported:
+  - gpio
+  - i2c
+  - spi
+  - watchdog
+  - adc
+  - dac
diff --git a/boards/arm/ronoth_lodev/ronoth_lodev_defconfig b/boards/arm/ronoth_lodev/ronoth_lodev_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..e1175de14e1b59009b864f5502141775a4a4ed26
--- /dev/null
+++ b/boards/arm/ronoth_lodev/ronoth_lodev_defconfig
@@ -0,0 +1,33 @@
+# Ronoth LoDev board configuration
+# Copyright (c) 2021 Dean Weiten <dmw@weiten.com>
+# SPDX-License-Identifier: Apache-2.0
+
+# Zephyr Kernel Configuration
+CONFIG_SOC_SERIES_STM32L0X=y
+
+# Platform Configuration
+CONFIG_SOC_STM32L073XX=y
+
+# General Kernel Options
+CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=16000000
+
+# Enable MPU
+CONFIG_ARM_MPU=y
+
+# Serial Drivers
+CONFIG_SERIAL=y
+CONFIG_UART_INTERRUPT_DRIVEN=y
+# enable console
+CONFIG_CONSOLE=y
+CONFIG_UART_CONSOLE=y
+
+# Pinmux Driver
+CONFIG_PINMUX=y
+
+# GPIO Controller
+CONFIG_GPIO=y
+
+# Clock configuration
+CONFIG_CLOCK_CONTROL=y
+# SYSCLK selection
+CONFIG_CLOCK_STM32_SYSCLK_SRC_HSI=y
diff --git a/boards/arm/stm32l562e_dk/CMakeLists.txt b/boards/arm/stm32l562e_dk/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..009a6cab30bade001e59fb6aa4a47bd03a28a9ad
--- /dev/null
+++ b/boards/arm/stm32l562e_dk/CMakeLists.txt
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: Apache-2.0
+
+if(${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "zephyr")
+  set(COMPILER_FULL_PATH ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc)
+elseif(${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "gnuarmemb")
+  set(COMPILER_FULL_PATH ${GNUARMEMB_TOOLCHAIN_PATH}/bin/arm-none-eabi-gcc)
+endif()
+
+if(CONFIG_BUILD_WITH_TFM)
+  set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts
+    #Execute post build script postbuild.sh
+    COMMAND ${CMAKE_BINARY_DIR}/tfm/postbuild.sh ${COMPILER_FULL_PATH}
+  )
+endif()
diff --git a/boards/arm/stm32l562e_dk/Kconfig.defconfig b/boards/arm/stm32l562e_dk/Kconfig.defconfig
index c35d42fa046d2ceaf4f83924e382dfd72bf195f8..74798165fc79605a4c8e32864b6d0405487a0912 100644
--- a/boards/arm/stm32l562e_dk/Kconfig.defconfig
+++ b/boards/arm/stm32l562e_dk/Kconfig.defconfig
@@ -32,4 +32,16 @@ config BT_HCI_VS_EXT
 
 endif # BT
 
+if TRUSTED_EXECUTION_NONSECURE
+
+# Get flash configuration for NS image from dts flash partition
+config USE_DT_CODE_PARTITION
+	default y
+
+config TFM_ISOLATION_LEVEL
+	default 2
+	depends on BUILD_WITH_TFM
+
+endif # TRUSTED_EXECUTION_NONSECURE
+
 endif # BOARD_STM32L562E_DK
diff --git a/boards/arm/stm32l562e_dk/board.cmake b/boards/arm/stm32l562e_dk/board.cmake
index 4e000bdbf822c95f2d1b96162bae5d0a6f5849aa..ddc46d4622c13d385fa284a2d63ba292646aa10a 100644
--- a/boards/arm/stm32l562e_dk/board.cmake
+++ b/boards/arm/stm32l562e_dk/board.cmake
@@ -1,3 +1,13 @@
+if(CONFIG_BUILD_WITH_TFM)
+  set(TFM_FLASH_BASE_ADDRESS 0x0C000000)
+
+  if (CONFIG_HAS_FLASH_LOAD_OFFSET)
+    MATH(EXPR TFM_HEX_BASE_ADDRESS_NS "${TFM_FLASH_BASE_ADDRESS}+${CONFIG_FLASH_LOAD_OFFSET}")
+  else()
+    set(TFM_HEX_BASE_ADDRESS_NS ${TFM_TFM_FLASH_BASE_ADDRESS})
+  endif()
+endif()
+
 set_ifndef(BOARD_DEBUG_RUNNER pyocd)
 set_ifndef(BOARD_FLASH_RUNNER pyocd)
 
diff --git a/boards/arm/stm32l562e_dk/doc/index.rst b/boards/arm/stm32l562e_dk/doc/index.rst
index 6e4ae4589ca41f7c9c443646fb0ce82a6df0b560..8c36423ceca13bf95b99fe37517cc4006efc2f05 100644
--- a/boards/arm/stm32l562e_dk/doc/index.rst
+++ b/boards/arm/stm32l562e_dk/doc/index.rst
@@ -166,6 +166,8 @@ The Zephyr stm32l562e_dk board configuration supports the following hardware fea
 +-----------+------------+-------------------------------------+
 | SPI       | on-chip    | spi                                 |
 +-----------+------------+-------------------------------------+
+| TrustZone | on-chip    | Trusted Firmware-M                  |
++-----------+------------+-------------------------------------+
 
 Other hardware features are not yet supported on this Zephyr port.
 
@@ -254,6 +256,20 @@ You should see the following message on the console:
 
    Hello World! stm32l562e_dk
 
+Building Secure/Non-Secure Zephyr applications with Arm |reg| TrustZone |reg|
+-----------------------------------------------------------------------------
+
+The TF-M integration sample :ref:`tfm_ipc` can be run on a STM32L562E-DK Discovery,
+using the ``stm32l562e_dk_ns`` target. When building a ``*_ns`` image with TF-M,
+a ``build/tfm/postbuild.sh`` bash script will be run automatically as a post-build step
+to make some required flash layout changes. The ``build/tfm/regression.sh`` script will
+need to be run to perform device initialization, and then run ``west flash --hex-file build/tfm_merged.hex``
+to flash the board.
+
+Check the ``build/tfm`` directory to ensure that the commands required by these scripts
+(``readlink``, etc.) are available on your system. Please also check ``STM32_Programmer_CLI``
+used for initialization is available in the PATH.
+
 Debugging
 =========
 
diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk.dts b/boards/arm/stm32l562e_dk/stm32l562e_dk.dts
index f18d240a45574b38e2183ca67bfa6489a8464917..14e5ca88325846d3b15ba183b4421b36fe3f6b13 100644
--- a/boards/arm/stm32l562e_dk/stm32l562e_dk.dts
+++ b/boards/arm/stm32l562e_dk/stm32l562e_dk.dts
@@ -26,3 +26,7 @@
 		sw0 = &user_button;
 	};
 };
+
+&usart1 {
+	pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>;
+};
diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi
index d083f9e759e45dc0a49cf9efcad1c513bed34e22..1b6c356ba1bb3dcee96830dbc9852351bb87b7d0 100644
--- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi
+++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi
@@ -31,7 +31,6 @@
 };
 
 &usart1 {
-	pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>;
 	current-speed = <115200>;
 	status = "okay";
 };
diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns.dts b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns.dts
new file mode 100644
index 0000000000000000000000000000000000000000..1d9fba58fe629c56fe1c155915075ca18298f84d
--- /dev/null
+++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Yestin Sun
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/dts-v1/;
+#include "stm32l562e_dk_common.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32L562E-DK Discovery board";
+	compatible = "st,stm32l562e-dk";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	chosen {
+		zephyr,console = &usart1;
+		zephyr,shell-uart = &usart1;
+		zephyr,sram = &sram0;
+		zephyr,flash = &flash0;
+	};
+
+	aliases {
+		led0 = &green_led_10;
+		sw0 = &user_button;
+	};
+};
diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns.yaml b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..31d1a5b32caaa56930a0a415386eab21051eaa1e
--- /dev/null
+++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns.yaml
@@ -0,0 +1,13 @@
+identifier: stm32l562e_dk_ns
+name: ST STM32L562E-DK Discovery non secure
+type: mcu
+arch: arm
+toolchain:
+  - zephyr
+  - gnuarmemb
+supported:
+  - gpio
+  - i2c
+  - lsm6dso
+ram: 192
+flash: 512
diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..7127c3c1999e93d7ee20d80284e99ff934cde1c0
--- /dev/null
+++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: Apache-2.0
+
+CONFIG_SOC_SERIES_STM32L5X=y
+CONFIG_SOC_STM32L562XX=y
+# 110MHz system clock
+CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=110000000
+
+# enable uart driver
+CONFIG_SERIAL=y
+
+# enable pinmux
+CONFIG_PINMUX=y
+
+# enable GPIO
+CONFIG_GPIO=y
+
+# clock configuration
+CONFIG_CLOCK_CONTROL=y
+# SYSCLK selection
+CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL=y
+# PLL configuration
+CONFIG_CLOCK_STM32_PLL_SRC_MSI=y
+CONFIG_CLOCK_STM32_MSI_RANGE=6
+# produce 110MHz clock at PLL output
+CONFIG_CLOCK_STM32_PLL_M_DIVISOR=1
+CONFIG_CLOCK_STM32_PLL_N_MULTIPLIER=55
+CONFIG_CLOCK_STM32_PLL_P_DIVISOR=7
+CONFIG_CLOCK_STM32_PLL_Q_DIVISOR=2
+CONFIG_CLOCK_STM32_PLL_R_DIVISOR=2
+CONFIG_CLOCK_STM32_AHB_PRESCALER=1
+CONFIG_CLOCK_STM32_APB1_PRESCALER=1
+CONFIG_CLOCK_STM32_APB2_PRESCALER=1
+
+# console
+CONFIG_CONSOLE=y
+CONFIG_UART_CONSOLE=y
+
+# Enable MPU
+CONFIG_ARM_MPU=y
+
+CONFIG_ARM_TRUSTZONE_M=y
+CONFIG_CORTEX_M_SYSTICK=y
+CONFIG_RUNTIME_NMI=y
+CONFIG_TRUSTED_EXECUTION_NONSECURE=y
diff --git a/boards/xtensa/esp32/esp32.dts b/boards/xtensa/esp32/esp32.dts
index f598f07c5d8c15c538de3e04ca074417cd156530..cb0f691b4c59466e63056a56e93a3c3ac9b19ecc 100644
--- a/boards/xtensa/esp32/esp32.dts
+++ b/boards/xtensa/esp32/esp32.dts
@@ -114,4 +114,14 @@
 
 &flash0 {
 	status = "okay";
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		storage_partition: partition@9000 {
+			label = "storage";
+			reg = <0x00009000 0x00006000>;
+		};
+	};
 };
diff --git a/boards/xtensa/esp32/esp32.yaml b/boards/xtensa/esp32/esp32.yaml
index 7f0c20d3b468d5eb9b32fd237213e48b7d85e07e..c6b3147636f2e82763814c9224e5aaeaa58dde2b 100644
--- a/boards/xtensa/esp32/esp32.yaml
+++ b/boards/xtensa/esp32/esp32.yaml
@@ -10,3 +10,4 @@ supported:
   - watchdog
   - uart
   - pinmux
+  - nvs
diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake
index d00e1db1d4fd165e2271ef15147a56e4ad6514ae..fb17aed1d5b4c2e96cd2c06a9defb5300f95b5e8 100644
--- a/cmake/app/boilerplate.cmake
+++ b/cmake/app/boilerplate.cmake
@@ -224,8 +224,6 @@ if(NOT (REVISION_SEPARATOR_INDEX EQUAL -1))
   string(SUBSTRING ${BOARD} 0 ${REVISION_SEPARATOR_INDEX} BOARD)
 endif()
 
-zephyr_boilerplate_watch(BOARD)
-
 set(BOARD_MESSAGE "Board: ${BOARD}")
 
 if(DEFINED ENV{ZEPHYR_BOARD_ALIASES})
@@ -243,6 +241,8 @@ if(${BOARD}_DEPRECATED)
   message(WARNING "Deprecated BOARD=${BOARD_DEPRECATED} name specified, board automatically changed to: ${BOARD}.")
 endif()
 
+zephyr_boilerplate_watch(BOARD)
+
 foreach(root ${BOARD_ROOT})
   # Check that the board root looks reasonable.
   if(NOT IS_DIRECTORY "${root}/boards")
diff --git a/cmake/linker/arcmwdt/target.cmake b/cmake/linker/arcmwdt/target.cmake
index 808ea3a199863bd85269cabdf92f9995703eb9de..4b7865fb98e335be755c3679138b9179244678c5 100644
--- a/cmake/linker/arcmwdt/target.cmake
+++ b/cmake/linker/arcmwdt/target.cmake
@@ -49,7 +49,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
     ${current_defines}
     ${linker_pass_define}
     ${LINKER_SCRIPT}
-    -P
+    -E
     -o ${linker_script_gen}
     VERBATIM
     WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
diff --git a/doc/application/index.rst b/doc/application/index.rst
index df4bed9441651eed48f34bcb3aad09c1f1746e06..ed35ead376bdbab68211d307e252339f630edc26 100644
--- a/doc/application/index.rst
+++ b/doc/application/index.rst
@@ -1084,7 +1084,7 @@ RTOS Awareness
 
 Support for Zephyr RTOS awareness is implemented in `pyOCD v0.11.0`_ and later.
 It is compatible with GDB PyOCD Debugging in Eclipse, but you must enable
-CONFIG_OPENOCD_SUPPORT=y in your application.
+CONFIG_DEBUG_THREAD_INFO=y in your application.
 
 .. _cmake-details:
 
diff --git a/doc/guides/porting/arch.rst b/doc/guides/porting/arch.rst
index 8ca43d2e94315285375150edaf1553f7bd41f3e6..6002c00dbd74474ef1552c788450ee124b419f98 100644
--- a/doc/guides/porting/arch.rst
+++ b/doc/guides/porting/arch.rst
@@ -824,8 +824,6 @@ on MMU systems and uncommon on MPU systems:
 
 * :c:func:`arch_mem_domain_partition_remove`
 
-* :c:func:`arch_mem_domain_destroy`
-
 Please see the doxygen documentation of these APIs for details.
 
 In addition to implementing these APIs, there are some other tasks as well:
diff --git a/doc/guides/west/built-in.rst b/doc/guides/west/built-in.rst
index e5591ac32385b0e0758fa545decf7187626a1622..3eb2052885891ec47773730f4f109f813a2bdf45 100644
--- a/doc/guides/west/built-in.rst
+++ b/doc/guides/west/built-in.rst
@@ -52,10 +52,12 @@ and check out the ``v1.14.0`` release. This command creates
 <west-config>` to ``zephyr`` to record the location of the manifest
 repository in the workspace. The default manifest file location is used.
 
-The ``-m`` option defaults to
-``https://github.com/zephyrproject-rtos/zephyr``. The ``--mr`` option
-defaults to ``master``. The ``--mf`` option defaults to ``west.yml``. If no
-``directory`` is given, the current working directory is used.
+The ``-m`` option defaults to ``https://github.com/zephyrproject-rtos/zephyr``.
+The ``--mf`` option defaults to ``west.yml``. Since west v0.10.1, west will use
+the default branch in the manifest repository unless the ``--mr`` option
+is used to override it. (In prior versions, ``--mr`` defaulted to ``master``.)
+
+If no ``directory`` is given, the current working directory is used.
 
 **Option 2**: to create a workspace around an existing local manifest
 repository, use:
diff --git a/doc/guides/west/manifest.rst b/doc/guides/west/manifest.rst
index 2058af780cf46845f29a9fcdcb48071960a55e7b..6511a599a882f74a9637ab9474e318443c36e7ff 100644
--- a/doc/guides/west/manifest.rst
+++ b/doc/guides/west/manifest.rst
@@ -1213,7 +1213,7 @@ Example 1.2: "Rolling release" Zephyr downstream
 ------------------------------------------------
 
 This is similar to :ref:`west-manifest-ex1.1`, except we'll use ``revision:
-master`` for the zephyr repository:
+main`` for the zephyr repository:
 
 .. code-block:: yaml
 
@@ -1225,7 +1225,7 @@ master`` for the zephyr repository:
      projects:
        - name: zephyr
          remote: zephyrproject-rtos
-         revision: master
+         revision: main
          import: true
 
 You can create the workspace in the same way:
@@ -1238,13 +1238,13 @@ You can create the workspace in the same way:
 
 This time, whenever you run ``west update``, the special :ref:`manifest-rev
 <west-manifest-rev>` branch in the ``zephyr`` repository will be updated to
-point at a newly fetched ``master`` branch tip from the URL
+point at a newly fetched ``main`` branch tip from the URL
 https://github.com/zephyrproject-rtos/zephyr.
 
 The contents of :file:`zephyr/west.yml` at the new ``manifest-rev`` will then
 be used to import projects from Zephyr. This lets you stay up to date with the
 latest changes in the Zephyr project. The cost is that running ``west update``
-will not produce reproducible results, since the remote ``master`` branch can
+will not produce reproducible results, since the remote ``main`` branch can
 change every time you run it.
 
 It's also important to understand that west **ignores your working tree's**
@@ -1341,7 +1341,7 @@ Here is an example:
          revision: v1.0
          import: west.yml
        - name: project-2
-         revision: master
+         revision: main
          import: p2-manifests
      self:
        import: submanifests
@@ -1351,7 +1351,8 @@ This will import the following:
 - the contents of :file:`project-1/west.yml` at ``manifest-rev``, which points
   at tag ``v1.0`` after running ``west update``
 - any YAML files in the directory tree :file:`project-2/p2-manifests`
-  at the latest ``master``, as fetched by ``west update``, sorted by file name
+  at the latest commit in the ``main`` branch, as fetched by ``west update``,
+  sorted by file name
 - YAML files in :file:`submanifests` in your manifest repository,
   as they appear on your file system, sorted by file name
 
@@ -1405,8 +1406,8 @@ them all in a single manifest repository, like this:
 
 You want to add all the files in :file:`my-repo/submanifests` to the main
 manifest file, :file:`my-repo/west.yml`, in addition to projects in
-:file:`zephyr/west.yml`. You want to track the latest mainline master
-instead of using a fixed revision.
+:file:`zephyr/west.yml`. You want to track the latest development code
+in the Zephyr repository's ``main`` branch instead of using a fixed revision.
 
 Here's how:
 
@@ -1420,6 +1421,7 @@ Here's how:
      projects:
        - name: zephyr
          remote: zephyrproject-rtos
+         revision: main
          import: true
      self:
        import: submanifests
diff --git a/doc/guides/west/release-notes.rst b/doc/guides/west/release-notes.rst
index 6dfc9d14db27e226d3655bc2fb12376c0dc3cc54..65ae43d2e8ee2f4612bb73ab262cef4890753c88 100644
--- a/doc/guides/west/release-notes.rst
+++ b/doc/guides/west/release-notes.rst
@@ -1,6 +1,17 @@
 West Release Notes
 ##################
 
+v0.10.1
+*******
+
+New features:
+
+- The :ref:`west-init` command's ``--manifest-rev`` (``--mr``) option no longer
+  defaults to ``master``. Instead, the command will query the repository for
+  its default branch name and use that instead. This allows users to move from
+  ``master`` to ``main`` without breaking scripts that do not provide this
+  option.
+
 v0.10.0
 *******
 
diff --git a/doc/releases/release-notes-2.6.rst b/doc/releases/release-notes-2.6.rst
index b215716eeb5bec439bc5d9f3940cc0bac52d5450..f8c14930743f5ca7f71e4e98aa6fbbeb76ed7a1a 100644
--- a/doc/releases/release-notes-2.6.rst
+++ b/doc/releases/release-notes-2.6.rst
@@ -51,15 +51,28 @@ Deprecated in this release
   :c:macro:`DT_INST_IO_CHANNELS_LABEL` were deprecated in favor of utilizing
   :c:macro:`DT_IO_CHANNELS_CTLR` and variants.
 
+* :c:macro:`DT_DMAS_LABEL_BY_IDX`,
+  :c:macro:`DT_DMAS_LABEL_BY_NAME`,
+  :c:macro:`DT_INST_DMAS_LABEL_BY_IDX`, and
+  :c:macro:`DT_INST_DMAS_LABEL_BY_NAME` were deprecated in favor of utilizing
+  :c:macro:`DT_DMAS_CTLR` and variants.
+
 * USB HID specific macros in ``<include/usb/class/usb_hid.h>`` are deprecated
   in favor of new common HID macros defined in ``<include/usb/class/hid.h>``.
 
+* The ``CONFIG_OPENOCD_SUPPORT`` Kconfig option has been deprecated in favor
+  of ``CONFIG_DEBUG_THREAD_INFO``.
+
 ==========================
 
 Removed APIs in this release
 
 * Removed support for the old zephyr integer typedefs (u8_t, u16_t, etc...).
 
+* Removed support for k_mem_domain_destroy and k_mem_domain_remove_thread
+
+* Removed support for counter_read and counter_get_max_relative_alarm
+
 ============================
 
 Stable API changes in this release
diff --git a/doc/security/index.rst b/doc/security/index.rst
index 328eb54994510f82e458e0b46f995d8d4d2419ff..2ae92f7f572242e41d6bdb58d92f539ecefe65a2 100644
--- a/doc/security/index.rst
+++ b/doc/security/index.rst
@@ -11,6 +11,7 @@ for ensuring security is addressed within the Zephyr project.
    :glob:
 
    security-overview.rst
+   reporting.rst
    secure-coding.rst
    sensor-threat.rst
    hardening-tool.rst
diff --git a/doc/security/reporting.rst b/doc/security/reporting.rst
new file mode 100644
index 0000000000000000000000000000000000000000..76f40b1b04f78225e4064d70d298f72a4e289877
--- /dev/null
+++ b/doc/security/reporting.rst
@@ -0,0 +1,188 @@
+.. _reporting:
+
+Security Vulnerability Reporting
+################################
+
+Introduction
+============
+
+Vulnerabilities to the Zephyr project may be reported via email to the
+vulnerabilities@zephyrproject.org mailing list.  These reports will be
+acknowledged and analyzed by the security response team within 1 week.
+Each vulnerability will be entered into the Zephyr Project security
+tracking JIRA_.  The original submitter will be granted permission to
+view the issues that they have reported.
+
+.. _JIRA: https://zephyrprojectsec.atlassian.net/
+
+Reporters may also submit reports by directly submitting them to the
+Zephyr Product security tracking JIRA.
+
+Security Issue Management
+=========================
+
+Issues within this bug tracking system will transition through a
+number of states according to this diagram:
+
+.. figure:: media/zepsec-workflow.png
+
+- New: This state represents new reports that have been entered
+  directly by a reporter.  When entered by the response team in
+  response to an email, the issue shall be transitioned directly to
+  Triage.
+
+- Triage: This issue is awaiting Triage by the response team.  The
+  response team will analyze the issue, determine a responsible
+  entity, assign the JIRA ticket to that individual, and move the
+  issue to the Assigned state.  Part of triage will be to set the
+  issue's priority.
+
+- Assigned: The issue has been assigned, and is awaiting a fix by the
+  assignee.
+
+- Review: Once there is a Zephyr pull request for the issue, the PR
+  link will be added to a comment in the issue, and the issue moved to
+  the Review state.
+
+- Accepted: Indicates that this issue has been merged into the
+  appropriate branch within Zephyr.
+
+- Release: The PR has been included in a released version of Zephyr.
+
+- Public: The embargo period has ended.  The issue will be made
+  publically visible, the associated CVE updated, and the
+  vulnerabilities page in the docs updated to include the detailed
+  information.
+
+The issues created in this JIRA instance are kept private, due to the
+sensitive nature of security reports.  The issues are only visible to
+certain parties:
+
+- Members of the PSIRT mailing list
+
+- the reporter
+
+- others, as proposed and ratified by the Zephyr Security
+  Subcommittee.  In the general case, this will include:
+
+  - The code owner responsible for the fix.
+
+  - The Zephyr release owners for the relevant releases affected by
+    this vulnerability.
+
+The Zephyr Security Subcommittee shall review the reported
+vulnerabilities during any meeting with more than three people in
+attendance.  During this review, they shall determine if new issues
+need to be embargoed.
+
+The guideline for embargo will be based on: 1. Severity of the issue,
+and 2. Exploitability of the issue.  Issues that the subcommittee
+decides do not need an embargo will be reproduced in the regular
+Zephyr project bug tracking system, and a comment added to the JIRA
+issue pointing to the bug tracking issue.  These issues will be marked
+as being tracked within the Zephyr bug tracking system.
+
+Security sensitive vulnerabilities shall be made public after an
+embargo period of at most 90 days.  The intent is to allow 30 days
+within the Zephyr project to fix the issues, and 60 days for external
+parties building products using Zephyr to be able to apply and
+distribute these fixes.
+
+Fixes to the code shall be made through pull requests PR in the Zephyr
+project github.  Developers shall make an attempt to not reveal the
+sensitive nature of what is being fixed, and shall not refer to CVE
+numbers that have been assigned to the issue.  The developer instead
+should merely describe what has been fixed.
+
+The security subcommittee will maintain information mapping embargoed
+CVEs to these PRs (this information is within the JIRA issues), and
+produce regular reports of the state of security issues.
+
+Each JIRA issue that is considered a security vulnerability shall be
+assigned a CVE number.  As fixes are created, it may be necessary to
+allocate additional CVE numbers, or to retire numbers that were
+assigned.
+
+Vulnerability Notification
+==========================
+
+Each Zephyr release shall contain a report of CVEs that were fixed in
+that release.  Because of the sensitive nature of these
+vulnerabilities, the release shall merely include a list of CVEs that
+have been fixed.  After the embargo period, the vulnerabilities page
+shall be updated to include additional details of these
+vulnerabilities.  The vulnerability page shall give credit to the
+reporter(s) unless a reporter specifically requests anonymity.
+
+The Zephyr project shall maintain a vulnerability-alerts mailing list.
+This list will be seeded initially with a contact from each project
+member.  Additional parties can request to join this list by filling
+out the form at the `Vulnerability Registry`_.  These parties will be
+vetted by the project director to determine that they have a
+legimitate interest in knowing about security vulnerabilities during
+the embargo period.
+
+.. _Vulnerability Registry: https://www.zephyrproject.org/vulnerability-registry/ 
+
+Periodically, the security subcommittee will send information to this
+mailing list describing known embargoed issues, and their backport
+status within the project.  This information is intended to allow them
+to determine if they need to backport these changes to any internal
+trees.
+
+When issues have been triaged, this list will be informed of:
+
+- The Zephyr Project security JIRA link (ZEPSEC).
+
+- The CVE number assigned.
+
+- The subsystem involved.
+
+- The severity of the issue.
+
+After acceptance of a PR fixing the issue (merged), in addition to the
+above, the list will be informed of:
+
+- The association between the CVE number and the PR fixing it.
+
+- Backport plans within the Zephyr project.
+
+Backporting of Security Vulnerabilities
+=======================================
+
+Each security issue fixed within zephyr shall be backported to the
+following releases:
+
+- The current Long Term Stable (LTS) release.
+
+- The most recent two releases.
+
+The developer of the fix shall be responsible for any necessary
+backports, and apply them to any of the above listed release branches,
+unless the fix does not apply (the vulnerability was introduced after
+this release was made).
+
+Backports will be tracked on the security JIRA instance using a
+subtask issue of type "backport".
+
+Need to Know
+============
+
+Due to the sensitive nature of security vulnerabilities, it is
+important to share details and fixes only with those parties that have
+a need to know.  The following parties will need to know details about
+security vulnerabilities before the embargo period ends:
+
+- Maintainers will have access to all information within their domain
+  area only.
+
+- The current release manager, and the release manager for historical
+  releases affected by the vulnerability (see backporting above).
+
+- The Project Security Incident Response (PSIRT) team will have full
+  access to information.  The PSIRT is made up of representatives from
+  platinum members, and volunteers who do work on triage from other
+  members.
+
+- As needed, release managers and maintainers may be invited to attend
+  additional security meetings to discuss vulnerabilties.
diff --git a/doc/security/security-overview.rst b/doc/security/security-overview.rst
index 5adfd242a8473888a238888dba95a8cfea1c7262..38e347f4558bda1688a4149b305b07e8a0fb2818 100644
--- a/doc/security/security-overview.rst
+++ b/doc/security/security-overview.rst
@@ -478,8 +478,8 @@ The software security process includes:
    towards a security certification if required.
 
 -  **Security Issue Management** encompasses the evaluation of potential
-   system vulnerabilities and their mitigation as described in the
-   `Security Issue Management`_ Section.
+   system vulnerabilities and their mitigation as described in
+   :ref:`Security Issue Management <reporting>`.
 
 These criteria and tasks need to be integrated into the development
 process for secure software and shall be automated wherever possible. On
@@ -536,186 +536,8 @@ considered and documented.
 Security Vulnerability Reporting
 ================================
 
-Vulnerabilities to the Zephyr project may be reported via email to the
-vulnerabilities@zephyrproject.org mailing list.  These reports will be
-acknowledged and analyzed by the security response team within 1 week.
-Each vulnerability will be entered into the Zephyr Project security
-tracking JIRA_.  The original submitter will be granted permission to
-view the issues that they have reported.
-
-.. _JIRA: https://zephyrprojectsec.atlassian.net/
-
-Reporters may also submit reports by directly submitting them to the
-Zephyr Product security tracking JIRA.
-
-Security Issue Management
-=========================
-
-Issues within this bug tracking system will transition through a
-number of states according to this diagram:
-
-.. figure:: media/zepsec-workflow.png
-
-- New: This state represents new reports that have been entered
-  directly by a reporter.  When entered by the response team in
-  response to an email, the issue shall be transitioned directly to
-  Triage.
-
-- Triage: This issue is awaiting Triage by the response team.  The
-  response team will analyze the issue, determine a responsible
-  entity, assign the JIRA ticket to that individual, and move the
-  issue to the Assigned state.  Part of triage will be to set the
-  issue's priority.
-
-- Assigned: The issue has been assigned, and is awaiting a fix by the
-  assignee.
-
-- Review: Once there is a Zephyr pull request for the issue, the PR
-  link will be added to a comment in the issue, and the issue moved to
-  the Review state.
-
-- Accepted: Indicates that this issue has been merged into the
-  appropriate branch within Zephyr.
-
-- Release: The PR has been included in a released version of Zephyr.
-
-- Public: The embargo period has ended.  The issue will be made
-  publically visible, the associated CVE updated, and the
-  vulnerabilities page in the docs updated to include the detailed
-  information.
-
-The issues created in this JIRA instance are kept private, due to the
-sensitive nature of security reports.  The issues are only visible to
-certain parties:
-
-- Members of the PSIRT mailing list
-
-- the reporter
-
-- others, as proposed and ratified by the Zephyr Security
-  Subcommittee.  In the general case, this will include:
-
-  - The code owner responsible for the fix.
-
-  - The Zephyr release owners for the relevant releases affected by
-    this vulnerability.
-
-The Zephyr Security Subcommittee shall review the reported
-vulnerabilities during any meeting with more than three people in
-attendance.  During this review, they shall determine if new issues
-need to be embargoed.
-
-The guideline for embargo will be based on: 1. Severity of the issue,
-and 2. Exploitability of the issue.  Issues that the subcommittee
-decides do not need an embargo will be reproduced in the regular
-Zephyr project bug tracking system, and a comment added to the JIRA
-issue pointing to the bug tracking issue.  These issues will be marked
-as being tracked within the Zephyr bug tracking system.
-
-Security sensitive vulnerabilities shall be made public after an
-embargo period of at most 90 days.  The intent is to allow 30 days
-within the Zephyr project to fix the issues, and 60 days for external
-parties building products using Zephyr to be able to apply and
-distribute these fixes.
-
-Fixes to the code shall be made through pull requests PR in the Zephyr
-project github.  Developers shall make an attempt to not reveal the
-sensitive nature of what is being fixed, and shall not refer to CVE
-numbers that have been assigned to the issue.  The developer instead
-should merely describe what has been fixed.
-
-The security subcommittee will maintain information mapping embargoed
-CVEs to these PRs (this information is within the JIRA issues), and
-produce regular reports of the state of security issues.
-
-Each JIRA issue that is considered a security vulnerability shall be
-assigned a CVE number.  As fixes are created, it may be necessary to
-allocate additional CVE numbers, or to retire numbers that were
-assigned.
-
-Vulnerability Notification
-==========================
-
-Each Zephyr release shall contain a report of CVEs that were fixed in
-that release.  Because of the sensitive nature of these
-vulnerabilities, the release shall merely include a list of CVEs that
-have been fixed.  After the embargo period, the vulnerabilities page
-shall be updated to include additional details of these
-vulnerabilities.  The vulnerability page shall give credit to the
-reporter(s) unless a reporter specifically requests anonymity.
-
-The Zephyr project shall maintain a vulnerability-alerts mailing list.
-This list will be seeded initially with a contact from each project
-member.  Additional parties can request to join this list by filling
-out the form at the `Vulnerability Registry`_.  These parties will be
-vetted by the project director to determine that they have a
-legimitate interest in knowing about security vulnerabilities during
-the embargo period.
-
-.. _Vulnerability Registry: https://www.zephyrproject.org/vulnerability-registry/ 
-
-Periodically, the security subcommittee will send information to this
-mailing list describing known embargoed issues, and their backport
-status within the project.  This information is intended to allow them
-to determine if they need to backport these changes to any internal
-trees.
-
-When issues have been triaged, this list will be informed of:
-
-- The Zephyr Project security JIRA link (ZEPSEC).
-
-- The CVE number assigned.
-
-- The subsystem involved.
-
-- The severity of the issue.
-
-After acceptance of a PR fixing the issue (merged), in addition to the
-above, the list will be informed of:
-
-- The association between the CVE number and the PR fixing it.
-
-- Backport plans within the Zephyr project.
-
-Backporting of Security Vulnerabilities
-=======================================
-
-Each security issue fixed within zephyr shall be backported to the
-following releases:
-
-- The current Long Term Stable (LTS) release.
-
-- The most recent two releases.
-
-The developer of the fix shall be responsible for any necessary
-backports, and apply them to any of the above listed release branches,
-unless the fix does not apply (the vulnerability was introduced after
-this release was made).
-
-Backports will be tracked on the security JIRA instance using a
-subtask issue of type "backport".
-
-Need to Know
-============
-
-Due to the sensitive nature of security vulnerabilities, it is
-important to share details and fixes only with those parties that have
-a need to know.  The following parties will need to know details about
-security vulnerabilities before the embargo period ends:
-
-- Maintainers will have access to all information within their domain
-  area only.
-
-- The current release manager, and the release manager for historical
-  releases affected by the vulnerability (see backporting above).
-
-- The Project Security Incident Response (PSIRT) team will have full
-  access to information.  The PSIRT is made up of representatives from
-  platinum members, and volunteers who do work on triage from other
-  members.
-
-- As needed, release managers and maintainers may be invited to attend
-  additional security meetings to discuss vulnerabilties.
+Please see :ref:`reporting` for information on reporting security
+vulnerabilities.
 
 Threat Modeling and Mitigation
 ==============================
diff --git a/drivers/counter/Kconfig.stm32_rtc b/drivers/counter/Kconfig.stm32_rtc
index 7490aee3fc9ad1a35802668357330d0648c864b5..eeda1a6ea706dedc7f9b77d158b5ab06c61db31d 100644
--- a/drivers/counter/Kconfig.stm32_rtc
+++ b/drivers/counter/Kconfig.stm32_rtc
@@ -81,4 +81,11 @@ config COUNTER_RTC_STM32_BACKUP_DOMAIN_RESET
 	help
 	  Force a backup domain reset on startup
 
+config COUNTER_RTC_STM32_SAVE_VALUE_BETWEEN_RESETS
+	bool "Save rtc time value between resets"
+	default y
+	depends on !COUNTER_RTC_STM32_BACKUP_DOMAIN_RESET
+	help
+	  Do not reset the rtc time and date after each reset.
+
 endif # COUNTER_RTC_STM32
diff --git a/drivers/counter/counter_esp32.c b/drivers/counter/counter_esp32.c
index 09614c5685d82b7fd8eea4fc4e9eda1f1a0a5d37..3e29df7cadb1813828eacd52e5e7caec5568acd4 100644
--- a/drivers/counter/counter_esp32.c
+++ b/drivers/counter/counter_esp32.c
@@ -205,11 +205,6 @@ static uint32_t counter_esp32_get_top_value(const struct device *dev)
 	return DEV_CFG(dev)->counter_info.max_top_value;
 }
 
-static uint32_t counter_esp32_get_max_relative_alarm(const struct device *dev)
-{
-	return counter_esp32_get_top_value(dev);
-}
-
 static const struct counter_driver_api counter_api = {
 	.start = counter_esp32_start,
 	.stop = counter_esp32_stop,
@@ -219,7 +214,6 @@ static const struct counter_driver_api counter_api = {
 	.set_top_value = counter_esp32_set_top_value,
 	.get_pending_int = counter_esp32_get_pending_int,
 	.get_top_value = counter_esp32_get_top_value,
-	.get_max_relative_alarm = counter_esp32_get_max_relative_alarm
 };
 
 static void counter_esp32_isr(struct device *dev)
diff --git a/drivers/counter/counter_gecko_rtcc.c b/drivers/counter/counter_gecko_rtcc.c
index 3a8eb342c7bdb1f2f32ae13c1a6841e0ac4d2642..6d0e0c4ea075a40d42bd55d2df4fe0972958fdaa 100644
--- a/drivers/counter/counter_gecko_rtcc.c
+++ b/drivers/counter/counter_gecko_rtcc.c
@@ -153,13 +153,6 @@ static uint32_t counter_gecko_get_top_value(const struct device *dev)
 	return RTCC_ChannelCCVGet(1);
 }
 
-static uint32_t counter_gecko_get_max_relative_alarm(const struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return RTCC_ChannelCCVGet(1);
-}
-
 static int counter_gecko_set_alarm(const struct device *dev, uint8_t chan_id,
 				   const struct counter_alarm_cfg *alarm_cfg)
 {
@@ -327,7 +320,6 @@ static const struct counter_driver_api counter_gecko_driver_api = {
 	.set_top_value = counter_gecko_set_top_value,
 	.get_pending_int = counter_gecko_get_pending_int,
 	.get_top_value = counter_gecko_get_top_value,
-	.get_max_relative_alarm = counter_gecko_get_max_relative_alarm,
 };
 
 /* RTCC0 */
diff --git a/drivers/counter/counter_handlers.c b/drivers/counter/counter_handlers.c
index 2c15838e5e41ff570e70899ee4d2def69ced28e3..dcba663125dda5ca28e711135aa972d94eaa0a9b 100644
--- a/drivers/counter/counter_handlers.c
+++ b/drivers/counter/counter_handlers.c
@@ -129,13 +129,6 @@ static inline uint32_t z_vrfy_counter_get_max_top_value(const struct device *dev
 }
 #include <syscalls/counter_get_max_top_value_mrsh.c>
 
-static inline uint32_t z_vrfy_counter_get_max_relative_alarm(const struct device *dev)
-{
-	Z_OOPS(Z_SYSCALL_DRIVER_COUNTER(dev, get_max_relative_alarm));
-	return z_impl_counter_get_max_relative_alarm((const struct device *)dev);
-}
-#include <syscalls/counter_get_max_relative_alarm_mrsh.c>
-
 static inline uint32_t z_vrfy_counter_get_guard_period(const struct device *dev,
 							uint32_t flags)
 {
diff --git a/drivers/counter/counter_imx_epit.c b/drivers/counter/counter_imx_epit.c
index ab53fcbc377bca420e94b2b0ef4fc7cd7c2bfb04..f31a4c9d357d3caf59572332f61af2c55b42cdc3 100644
--- a/drivers/counter/counter_imx_epit.c
+++ b/drivers/counter/counter_imx_epit.c
@@ -134,11 +134,6 @@ static uint32_t imx_epit_get_top_value(const struct device *dev)
 	return EPIT_GetCounterLoadValue(base);
 }
 
-static uint32_t imx_epit_get_max_relative_alarm(const struct device *dev)
-{
-	return COUNTER_MAX_RELOAD;
-}
-
 static const struct counter_driver_api imx_epit_driver_api = {
 	.start = imx_epit_start,
 	.stop = imx_epit_stop,
@@ -146,7 +141,6 @@ static const struct counter_driver_api imx_epit_driver_api = {
 	.set_top_value = imx_epit_set_top_value,
 	.get_pending_int = imx_epit_get_pending_int,
 	.get_top_value = imx_epit_get_top_value,
-	.get_max_relative_alarm = imx_epit_get_max_relative_alarm,
 };
 
 #define COUNTER_IMX_EPIT_DEVICE(idx)					       \
diff --git a/drivers/counter/counter_ll_stm32_rtc.c b/drivers/counter/counter_ll_stm32_rtc.c
index bfed6c9e9fc6fb9e5d51c9175db268ccf2c650eb..049d65d907d7f8eece07c9096a2d340f9e013b19 100644
--- a/drivers/counter/counter_ll_stm32_rtc.c
+++ b/drivers/counter/counter_ll_stm32_rtc.c
@@ -246,15 +246,6 @@ static int rtc_stm32_set_top_value(const struct device *dev,
 
 }
 
-
-static uint32_t rtc_stm32_get_max_relative_alarm(const struct device *dev)
-{
-	const struct counter_config_info *info = dev->config;
-
-	return info->max_top_value;
-}
-
-
 void rtc_stm32_isr(const struct device *dev)
 {
 	struct rtc_stm32_data *data = DEV_DATA(dev);
@@ -359,9 +350,11 @@ static int rtc_stm32_init(const struct device *dev)
 
 	z_stm32_hsem_unlock(CFG_HW_RCC_SEMID);
 
+#if !defined(CONFIG_COUNTER_RTC_STM32_SAVE_VALUE_BETWEEN_RESETS)
 	if (LL_RTC_DeInit(RTC) != SUCCESS) {
 		return -EIO;
 	}
+#endif
 
 	if (LL_RTC_Init(RTC, ((LL_RTC_InitTypeDef *)
 			      &cfg->ll_rtc_config)) != SUCCESS) {
@@ -423,7 +416,6 @@ static const struct counter_driver_api rtc_stm32_driver_api = {
 		.set_top_value = rtc_stm32_set_top_value,
 		.get_pending_int = rtc_stm32_get_pending_int,
 		.get_top_value = rtc_stm32_get_top_value,
-		.get_max_relative_alarm = rtc_stm32_get_max_relative_alarm,
 };
 
 DEVICE_DT_INST_DEFINE(0, &rtc_stm32_init, device_pm_control_nop,
diff --git a/drivers/counter/counter_mchp_xec.c b/drivers/counter/counter_mchp_xec.c
index 8511f3ee983c84178ececa7c766f63654553db6e..9b3fa427ce5500bc53118486d5ea55c39e150b8d 100644
--- a/drivers/counter/counter_mchp_xec.c
+++ b/drivers/counter/counter_mchp_xec.c
@@ -241,13 +241,6 @@ static int counter_xec_set_top_value(const struct device *dev,
 	return ret;
 }
 
-static uint32_t counter_xec_get_max_relative_alarm(const struct device *dev)
-{
-	const struct counter_xec_config *counter_cfg = COUNTER_XEC_CONFIG(dev);
-
-	return counter_cfg->info.max_top_value;
-}
-
 static void counter_xec_isr(const struct device *dev)
 {
 	BTMR_Type *counter = COUNTER_XEC_REG_BASE(dev);
@@ -284,7 +277,6 @@ static const struct counter_driver_api counter_xec_api = {
 		.set_top_value = counter_xec_set_top_value,
 		.get_pending_int = counter_xec_get_pending_int,
 		.get_top_value = counter_xec_get_top_value,
-		.get_max_relative_alarm = counter_xec_get_max_relative_alarm,
 };
 
 static int counter_xec_init(const struct device *dev)
diff --git a/drivers/counter/counter_mcux_gpt.c b/drivers/counter/counter_mcux_gpt.c
index 515003ac0ee3f197fd1e98bc323e047e8dcccca8..2f0afce6226e1d19673cbae1dded684cf61d41cf 100644
--- a/drivers/counter/counter_mcux_gpt.c
+++ b/drivers/counter/counter_mcux_gpt.c
@@ -162,13 +162,6 @@ static uint32_t mcux_gpt_get_top_value(const struct device *dev)
 	return config->info.max_top_value;
 }
 
-static uint32_t mcux_gpt_get_max_relative_alarm(const struct device *dev)
-{
-	const struct mcux_gpt_config *config = dev->config;
-
-	return config->info.max_top_value;
-}
-
 static int mcux_gpt_init(const struct device *dev)
 {
 	const struct mcux_gpt_config *config = dev->config;
@@ -205,7 +198,6 @@ static const struct counter_driver_api mcux_gpt_driver_api = {
 	.set_top_value = mcux_gpt_set_top_value,
 	.get_pending_int = mcux_gpt_get_pending_int,
 	.get_top_value = mcux_gpt_get_top_value,
-	.get_max_relative_alarm = mcux_gpt_get_max_relative_alarm,
 };
 
 #define GPT_DEVICE_INIT_MCUX(n)						\
diff --git a/drivers/counter/counter_mcux_lptmr.c b/drivers/counter/counter_mcux_lptmr.c
index ffcdba3637bb778fb17eb6093ee7f1c4448c7ecd..381fff4d480ddab7f2c0038231712de53165abf3 100644
--- a/drivers/counter/counter_mcux_lptmr.c
+++ b/drivers/counter/counter_mcux_lptmr.c
@@ -103,14 +103,6 @@ static uint32_t mcux_lptmr_get_top_value(const struct device *dev)
 	return (config->base->CMR & LPTMR_CMR_COMPARE_MASK) + 1U;
 }
 
-static uint32_t mcux_lptmr_get_max_relative_alarm(const struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	/* Alarms not supported */
-	return 0;
-}
-
 static void mcux_lptmr_isr(const struct device *dev)
 {
 	const struct mcux_lptmr_config *config = dev->config;
@@ -156,7 +148,6 @@ static const struct counter_driver_api mcux_lptmr_driver_api = {
 	.set_top_value = mcux_lptmr_set_top_value,
 	.get_pending_int = mcux_lptmr_get_pending_int,
 	.get_top_value = mcux_lptmr_get_top_value,
-	.get_max_relative_alarm = mcux_lptmr_get_max_relative_alarm,
 };
 
 #define TO_LPTMR_CLK_SEL(val) _DO_CONCAT(kLPTMR_PrescalerClock_, val)
diff --git a/drivers/counter/counter_mcux_pit.c b/drivers/counter/counter_mcux_pit.c
index b0df43188626cfd9a9854429176db7c6acf180f8..105f79f93b0d08b2423b9cc31d79681a0277ca54 100644
--- a/drivers/counter/counter_mcux_pit.c
+++ b/drivers/counter/counter_mcux_pit.c
@@ -107,13 +107,6 @@ static uint32_t mcux_pit_get_pending_int(const struct device *dev)
 	return ((flags & mask) == mask);
 }
 
-static uint32_t mcux_pit_get_max_relative_alarm(const struct device *dev)
-{
-	const struct mcux_pit_config *config = dev->config;
-
-	return config->info.max_top_value;
-}
-
 static void mcux_pit_isr(const struct device *dev)
 {
 	const struct mcux_pit_config *config = dev->config;
@@ -208,7 +201,6 @@ static const struct counter_driver_api mcux_pit_driver_api = {
 	.cancel_alarm = mcux_pit_cancel_alarm,
 	.get_pending_int = mcux_pit_get_pending_int,
 	.get_top_value = mcux_pit_get_top_value,
-	.get_max_relative_alarm = mcux_pit_get_max_relative_alarm,
 };
 
 /*
diff --git a/drivers/counter/counter_mcux_rtc.c b/drivers/counter/counter_mcux_rtc.c
index daadf53adf2167c04dafbae00a521d3a6bed872f..56f9214c7e8f522d5515f8502e6aebff40f911b4 100644
--- a/drivers/counter/counter_mcux_rtc.c
+++ b/drivers/counter/counter_mcux_rtc.c
@@ -182,13 +182,6 @@ static uint32_t mcux_rtc_get_top_value(const struct device *dev)
 	return info->max_top_value;
 }
 
-static uint32_t mcux_rtc_get_max_relative_alarm(const struct device *dev)
-{
-	const struct counter_config_info *info = dev->config;
-
-	return info->max_top_value;
-}
-
 static void mcux_rtc_isr(const struct device *dev)
 {
 	const struct counter_config_info *info = dev->config;
@@ -258,7 +251,6 @@ static const struct counter_driver_api mcux_rtc_driver_api = {
 	.set_top_value = mcux_rtc_set_top_value,
 	.get_pending_int = mcux_rtc_get_pending_int,
 	.get_top_value = mcux_rtc_get_top_value,
-	.get_max_relative_alarm = mcux_rtc_get_max_relative_alarm,
 };
 
 static struct mcux_rtc_data mcux_rtc_data_0;
diff --git a/drivers/counter/counter_native_posix.c b/drivers/counter/counter_native_posix.c
index 8b657d11df13f584b4f9f0137462e7d1a0733771..5f240fd049f0c48c335316754afad7c77c09a78c 100644
--- a/drivers/counter/counter_native_posix.c
+++ b/drivers/counter/counter_native_posix.c
@@ -92,11 +92,6 @@ static uint32_t ctr_get_top_value(const struct device *dev)
 	return TOP_VALUE;
 }
 
-static uint32_t ctr_get_max_relative_alarm(const struct device *dev)
-{
-	return TOP_VALUE;
-}
-
 static int ctr_set_alarm(const struct device *dev, uint8_t chan_id,
 			 const struct counter_alarm_cfg *alarm_cfg)
 {
@@ -144,7 +139,6 @@ static const struct counter_driver_api ctr_api = {
 	.set_top_value = ctr_set_top_value,
 	.get_pending_int = ctr_get_pending_int,
 	.get_top_value = ctr_get_top_value,
-	.get_max_relative_alarm = ctr_get_max_relative_alarm,
 };
 
 static const struct counter_config_info ctr_config = {
diff --git a/drivers/counter/counter_nrfx_rtc.c b/drivers/counter/counter_nrfx_rtc.c
index 82ff82ec3e622c4a799ebb86352e869af4c1919c..c7c79359eda27cc3a165d7156ebb814c0752f30e 100644
--- a/drivers/counter/counter_nrfx_rtc.c
+++ b/drivers/counter/counter_nrfx_rtc.c
@@ -552,11 +552,6 @@ static uint32_t get_top_value(const struct device *dev)
 	return get_dev_data(dev)->top;
 }
 
-static uint32_t get_max_relative_alarm(const struct device *dev)
-{
-	return get_dev_data(dev)->top;
-}
-
 static uint32_t get_guard_period(const struct device *dev, uint32_t flags)
 {
 	return get_dev_data(dev)->guard_period;
@@ -647,7 +642,6 @@ static const struct counter_driver_api counter_nrfx_driver_api = {
 	.set_top_value = set_top_value,
 	.get_pending_int = get_pending_int,
 	.get_top_value = get_top_value,
-	.get_max_relative_alarm = get_max_relative_alarm,
 	.get_guard_period = get_guard_period,
 	.set_guard_period = set_guard_period,
 };
diff --git a/drivers/counter/counter_nrfx_timer.c b/drivers/counter/counter_nrfx_timer.c
index 9e0432415b09ba04ca0c428df56b0b99353d1db0..3281e547aa5cfa6306d3972a484e4e4408d0566f 100644
--- a/drivers/counter/counter_nrfx_timer.c
+++ b/drivers/counter/counter_nrfx_timer.c
@@ -82,11 +82,6 @@ static uint32_t get_top_value(const struct device *dev)
 	return nrf_timer_cc_get(get_nrfx_config(dev)->timer, TOP_CH);
 }
 
-static uint32_t get_max_relative_alarm(const struct device *dev)
-{
-	return get_top_value(dev);
-}
-
 static uint32_t read(const struct device *dev)
 {
 	NRF_TIMER_Type *timer = get_nrfx_config(dev)->timer;
@@ -379,7 +374,6 @@ static const struct counter_driver_api counter_nrfx_driver_api = {
 	.set_top_value = set_top_value,
 	.get_pending_int = get_pending_int,
 	.get_top_value = get_top_value,
-	.get_max_relative_alarm = get_max_relative_alarm,
 	.get_guard_period = get_guard_period,
 	.set_guard_period = set_guard_period,
 };
diff --git a/drivers/counter/counter_sam0_tc32.c b/drivers/counter/counter_sam0_tc32.c
index 9e4fc883f1fe6d6fcbf88e89b3542f0322e37eb0..c724556ee466f8b9b89923eac6ba9d1d5eb79218 100644
--- a/drivers/counter/counter_sam0_tc32.c
+++ b/drivers/counter/counter_sam0_tc32.c
@@ -305,11 +305,6 @@ static uint32_t counter_sam0_tc32_get_top_value(const struct device *dev)
 	return tc->CC[0].reg;
 }
 
-static uint32_t counter_sam0_tc32_get_max_relative_alarm(const struct device *dev)
-{
-	return counter_sam0_tc32_get_top_value(dev) - 1;
-}
-
 static void counter_sam0_tc32_isr(const struct device *dev)
 {
 	struct counter_sam0_tc32_data *data = DEV_DATA(dev);
@@ -402,7 +397,6 @@ static const struct counter_driver_api counter_sam0_tc32_driver_api = {
 	.set_top_value = counter_sam0_tc32_set_top_value,
 	.get_pending_int = counter_sam0_tc32_get_pending_int,
 	.get_top_value = counter_sam0_tc32_get_top_value,
-	.get_max_relative_alarm = counter_sam0_tc32_get_max_relative_alarm,
 };
 
 
diff --git a/drivers/counter/counter_xlnx_axi_timer.c b/drivers/counter/counter_xlnx_axi_timer.c
index 7597ceed5c904fc0c809cee339cae4650ed25326..1735e87ba5d3571c5968993dcb428eb4c08f21fa 100644
--- a/drivers/counter/counter_xlnx_axi_timer.c
+++ b/drivers/counter/counter_xlnx_axi_timer.c
@@ -256,13 +256,6 @@ static uint32_t xlnx_axi_timer_get_top_value(const struct device *dev)
 	return xlnx_axi_timer_read32(dev, TLR0_OFFSET);
 }
 
-static uint32_t xlnx_axi_timer_get_max_relative_alarm(const struct device *dev)
-{
-	const struct xlnx_axi_timer_config *config = dev->config;
-
-	return config->info.max_top_value;
-}
-
 static void xlnx_axi_timer_isr(const struct device *dev)
 {
 	struct xlnx_axi_timer_data *data = dev->data;
@@ -323,7 +316,6 @@ static const struct counter_driver_api xlnx_axi_timer_driver_api = {
 	.set_top_value = xlnx_axi_timer_set_top_value,
 	.get_pending_int = xlnx_axi_timer_get_pending_int,
 	.get_top_value = xlnx_axi_timer_get_top_value,
-	.get_max_relative_alarm = xlnx_axi_timer_get_max_relative_alarm,
 };
 
 #define XLNX_AXI_TIMER_INIT(n)						\
diff --git a/drivers/counter/maxim_ds3231.c b/drivers/counter/maxim_ds3231.c
index 233b584ba6e84f919be9630cbee871e7b492252f..3fbc529d99131306fd3734dc90e9ae243aadbb96 100644
--- a/drivers/counter/maxim_ds3231.c
+++ b/drivers/counter/maxim_ds3231.c
@@ -1281,11 +1281,6 @@ static int ds3231_counter_set_top_value(const struct device *dev,
 	return -ENOTSUP;
 }
 
-static uint32_t ds3231_counter_get_max_relative_alarm(const struct device *dev)
-{
-	return UINT32_MAX;
-}
-
 static const struct counter_driver_api ds3231_api = {
 	.start = ds3231_counter_start,
 	.stop = ds3231_counter_stop,
@@ -1295,7 +1290,6 @@ static const struct counter_driver_api ds3231_api = {
 	.set_top_value = ds3231_counter_set_top_value,
 	.get_pending_int = ds3231_counter_get_pending_int,
 	.get_top_value = ds3231_counter_get_top_value,
-	.get_max_relative_alarm = ds3231_counter_get_max_relative_alarm,
 };
 
 static const struct ds3231_config ds3231_0_config = {
diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c
index 9f7318414dda5a0ed106ae275af852724a8bda38..4951613fcc77d623d0ca26f42b3cc7bdd2762a33 100644
--- a/drivers/entropy/entropy_stm32.c
+++ b/drivers/entropy/entropy_stm32.c
@@ -127,6 +127,7 @@ static int random_byte_get(void)
 		} else {
 			retval = LL_RNG_ReadRandData32(
 						    entropy_stm32_rng_data.rng);
+			retval &= 0xFF;
 		}
 	}
 
diff --git a/drivers/espi/host_subs_npcx.c b/drivers/espi/host_subs_npcx.c
index 54140c31b39cb07a1c8b11c55cb04f5f28bd9964..b1bea00f7b8011cfa9e38d398d3e8e64dcfb7a81 100644
--- a/drivers/espi/host_subs_npcx.c
+++ b/drivers/espi/host_subs_npcx.c
@@ -962,6 +962,16 @@ void npcx_host_init_subs_host_domain(void)
 	LOG_DBG("Hos sub-modules configurations are done!");
 }
 
+void npcx_host_enable_access_interrupt(void)
+{
+	npcx_miwu_irq_enable(&host_sub_cfg.host_acc_wui);
+}
+
+void npcx_host_disable_access_interrupt(void)
+{
+	npcx_miwu_irq_disable(&host_sub_cfg.host_acc_wui);
+}
+
 int npcx_host_init_subs_core_domain(const struct device *host_bus_dev,
 							sys_slist_t *callbacks)
 {
@@ -1057,13 +1067,11 @@ int npcx_host_init_subs_core_domain(const struct device *host_bus_dev,
 	if (IS_ENABLED(CONFIG_PM)) {
 		/*
 		 * Configure the host access wake-up event triggered from a host
-		 * transaction on eSPI/LPC bus. No need for callback function.
+		 * transaction on eSPI/LPC bus. Do not enable it here. Or plenty
+		 * of interrupts will jam the system in S0.
 		 */
 		npcx_miwu_interrupt_configure(&host_sub_cfg.host_acc_wui,
 				NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_HIGH);
-
-		/* Enable irq of interrupt-input module */
-		npcx_miwu_irq_enable(&host_sub_cfg.host_acc_wui);
 	}
 
 	return 0;
diff --git a/drivers/gpio/gpio_mchp_xec.c b/drivers/gpio/gpio_mchp_xec.c
index acf6b859151de8fb64ce431dd90e6ab6e8afdb5b..9c5519be10490104d93e4c186343e37444e64d19 100644
--- a/drivers/gpio/gpio_mchp_xec.c
+++ b/drivers/gpio/gpio_mchp_xec.c
@@ -79,9 +79,11 @@ static int gpio_xec_configure(const struct device *dev,
 	 * PCRs for a given GPIO. There are no GPIO modules in Microchip SOCs!
 	 * Keep direction as input until last.
 	 * Clear input pad disable allowing input pad to operate.
+	 * Clear Power gate to allow pads to operate.
 	 */
 	mask |= MCHP_GPIO_CTRL_DIR_MASK;
 	mask |= MCHP_GPIO_CTRL_INPAD_DIS_MASK;
+	mask |= MCHP_GPIO_CTRL_PWRG_MASK;
 	pcr1 |= MCHP_GPIO_CTRL_DIR_INPUT;
 
 	/* Figure out the pullup/pulldown configuration and keep it in the
@@ -114,6 +116,11 @@ static int gpio_xec_configure(const struct device *dev,
 	mask |= MCHP_GPIO_CTRL_AOD_MASK;
 	pcr1 |= MCHP_GPIO_CTRL_AOD_DIS;
 
+	/* Make sure disconnected on first control register write */
+	if (flags == GPIO_DISCONNECTED) {
+		pcr1 |= MCHP_GPIO_CTRL_PWRG_OFF;
+	}
+
 	/* Now write contents of pcr1 variable to the PCR1 register that
 	 * corresponds to the GPIO being configured.
 	 * AOD is 1 and direction is input. HW will allow use to set the
@@ -133,13 +140,6 @@ static int gpio_xec_configure(const struct device *dev,
 		mask = MCHP_GPIO_CTRL_DIR_MASK;
 		pcr1 = MCHP_GPIO_CTRL_DIR_OUTPUT;
 		*current_pcr1 = (*current_pcr1 & ~mask) | pcr1;
-	} else if ((flags & GPIO_INPUT) != 0U) {
-		/* Already configured */
-	} else {
-		/*  GPIO disconnected */
-		mask |= MCHP_GPIO_CTRL_PWRG_MASK;
-		pcr1 |= MCHP_GPIO_CTRL_PWRG_OFF;
-		*current_pcr1 = (*current_pcr1 & ~mask) | pcr1;
 	}
 
 	return 0;
diff --git a/drivers/pinmux/CMakeLists.txt b/drivers/pinmux/CMakeLists.txt
index 13e1a53c34bbac54c06a3fec8bafec70fd8d0911..7118eab09b6f57cbbeed63ab9d33598a05de723d 100644
--- a/drivers/pinmux/CMakeLists.txt
+++ b/drivers/pinmux/CMakeLists.txt
@@ -9,7 +9,6 @@ zephyr_sources_ifdef(CONFIG_PINMUX_ITE_IT8XXX2     pinmux_ite_it8xxx2.c)
 zephyr_sources_ifdef(CONFIG_PINMUX_LPC11U6X        pinmux_lpc11u6x.c)
 zephyr_sources_ifdef(CONFIG_PINMUX_MCUX            pinmux_mcux.c)
 zephyr_sources_ifdef(CONFIG_PINMUX_MCUX_LPC        pinmux_mcux_lpc.c)
-zephyr_sources_ifdef(CONFIG_PINMUX_NPCX            pinmux_npcx.c)
 zephyr_sources_ifdef(CONFIG_PINMUX_RV32M1          pinmux_rv32m1.c)
 zephyr_sources_ifdef(CONFIG_PINMUX_SAM0            pinmux_sam0.c)
 zephyr_sources_ifdef(CONFIG_PINMUX_SIFIVE          pinmux_sifive.c)
diff --git a/drivers/pinmux/Kconfig b/drivers/pinmux/Kconfig
index 976be25905bafe7b56c8ea1bbe1fba0aaa1ebbea..1572fd92b24ba4e5c399b1f78398eabae3f91766 100644
--- a/drivers/pinmux/Kconfig
+++ b/drivers/pinmux/Kconfig
@@ -52,6 +52,4 @@ source "drivers/pinmux/Kconfig.stm32"
 
 source "drivers/pinmux/Kconfig.xec"
 
-source "drivers/pinmux/Kconfig.npcx"
-
 endif # PINMUX
diff --git a/drivers/pinmux/Kconfig.npcx b/drivers/pinmux/Kconfig.npcx
deleted file mode 100644
index 1ea93258af1a6627da2e78589d9b170b12c48028..0000000000000000000000000000000000000000
--- a/drivers/pinmux/Kconfig.npcx
+++ /dev/null
@@ -1,12 +0,0 @@
-# NPCX PINMUX driver configuration options
-
-# Copyright (c) 2020 Nuvoton Technology Corporation.
-# SPDX-License-Identifier: Apache-2.0
-
-config PINMUX_NPCX
-	bool "Nuvoton NPCX embedded controller (EC) pinmux driver"
-	depends on SOC_FAMILY_NPCX
-	help
-	  This option enables the pin-mux driver for NPCX family
-	  of processors.
-	  Say y if you wish to use pin-mux module on NPCX MCU.
diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt
index e17d1523c9dba6355d09b5093cb52e29c3010e8e..29c016387134b067d329dd61eb34de7ac951674a 100644
--- a/drivers/sensor/CMakeLists.txt
+++ b/drivers/sensor/CMakeLists.txt
@@ -63,6 +63,7 @@ add_subdirectory_ifdef(CONFIG_MS5837		ms5837)
 add_subdirectory_ifdef(CONFIG_OPT3001		opt3001)
 add_subdirectory_ifdef(CONFIG_PMS7003		pms7003)
 add_subdirectory_ifdef(CONFIG_QDEC_NRFX		qdec_nrfx)
+add_subdirectory_ifdef(CONFIG_QDEC_SAM		qdec_sam)
 add_subdirectory_ifdef(CONFIG_TEMP_NRF5		nrf5)
 add_subdirectory_ifdef(CONFIG_SHT3XD		sht3xd)
 add_subdirectory_ifdef(CONFIG_SI7006		si7006)
diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig
index 4e8c5f2130b1b34e6d904c646fd5222512ebbfbd..522efcfa89b1b523a169091f5a8c7e905938b134 100644
--- a/drivers/sensor/Kconfig
+++ b/drivers/sensor/Kconfig
@@ -168,6 +168,8 @@ source "drivers/sensor/pms7003/Kconfig"
 
 source "drivers/sensor/qdec_nrfx/Kconfig"
 
+source "drivers/sensor/qdec_sam/Kconfig"
+
 source "drivers/sensor/sht3xd/Kconfig"
 
 source "drivers/sensor/si7006/Kconfig"
diff --git a/drivers/sensor/qdec_sam/CMakeLists.txt b/drivers/sensor/qdec_sam/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f807d91e1de264fd35efbfd61750be3ab9fc7d6d
--- /dev/null
+++ b/drivers/sensor/qdec_sam/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright (c) 2021, Piotr Mienkowski
+#
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_library()
+
+zephyr_library_sources(qdec_sam.c)
diff --git a/drivers/sensor/qdec_sam/Kconfig b/drivers/sensor/qdec_sam/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..b2d043c41ee997e6559861f48c6e6f11270fd934
--- /dev/null
+++ b/drivers/sensor/qdec_sam/Kconfig
@@ -0,0 +1,12 @@
+# Atmel SAM MCU family Quadrature Decoder (TC) driver configuration options
+#
+# Copyright (c) 2021, Piotr Mienkowski
+# SPDX-License-Identifier: Apache-2.0
+#
+
+config QDEC_SAM
+	bool "Atmel SAM QDEC driver"
+	depends on SOC_FAMILY_SAM
+	default n
+	help
+	  Atmel SAM MCU family Quadrature Decoder (TC) driver.
diff --git a/drivers/sensor/qdec_sam/qdec_sam.c b/drivers/sensor/qdec_sam/qdec_sam.c
new file mode 100644
index 0000000000000000000000000000000000000000..05ebe293144ab83796ba490776a42f350be7dab0
--- /dev/null
+++ b/drivers/sensor/qdec_sam/qdec_sam.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2021, Piotr Mienkowski
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT atmel_sam_tc
+
+/** @file
+ * @brief Atmel SAM MCU family Quadrature Decoder (QDEC/TC) driver.
+ */
+
+#include <errno.h>
+#include <sys/__assert.h>
+#include <sys/util.h>
+#include <device.h>
+#include <init.h>
+#include <soc.h>
+#include <drivers/sensor.h>
+
+#include <logging/log.h>
+LOG_MODULE_REGISTER(qdec_sam, CONFIG_SENSOR_LOG_LEVEL);
+
+/* Device constant configuration parameters */
+struct qdec_sam_dev_cfg {
+	Tc *regs;
+	const struct soc_gpio_pin *pin_list;
+	uint8_t pin_list_size;
+	uint8_t periph_id[TCCHANNEL_NUMBER];
+};
+
+/* Device run time data */
+struct qdec_sam_dev_data {
+	uint16_t position;
+};
+
+#define DEV_NAME(dev) ((dev)->name)
+#define DEV_CFG(dev) \
+	((const struct qdec_sam_dev_cfg *const)(dev)->config)
+#define DEV_DATA(dev) \
+	((struct qdec_sam_dev_data *const)(dev)->data)
+
+static int qdec_sam_fetch(const struct device *dev, enum sensor_channel chan)
+{
+	const struct qdec_sam_dev_cfg *const dev_cfg = DEV_CFG(dev);
+	struct qdec_sam_dev_data *const dev_data = DEV_DATA(dev);
+	Tc *const tc = dev_cfg->regs;
+	TcChannel *tc_ch0 = &tc->TC_CHANNEL[0];
+
+	/* Read position register content */
+	dev_data->position = tc_ch0->TC_CV;
+
+	return 0;
+}
+
+static int qdec_sam_get(const struct device *dev, enum sensor_channel chan,
+			struct sensor_value *val)
+{
+	struct qdec_sam_dev_data *const dev_data = DEV_DATA(dev);
+
+	if (chan == SENSOR_CHAN_ROTATION) {
+		val->val1 = dev_data->position;
+		val->val2 = 0;
+	} else {
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+static void qdec_sam_start(Tc *const tc)
+{
+	TcChannel *tc_ch0 = &tc->TC_CHANNEL[0];
+
+	/* Enable Channel 0 Clock and reset counter*/
+	tc_ch0->TC_CCR =  TC_CCR_CLKEN
+			| TC_CCR_SWTRG;
+}
+
+static void qdec_sam_configure(const struct device *dev)
+{
+	const struct qdec_sam_dev_cfg *const dev_cfg = DEV_CFG(dev);
+	Tc *const tc = dev_cfg->regs;
+	TcChannel *tc_ch0 = &tc->TC_CHANNEL[0];
+
+	/* Clock, Trigger Edge, Trigger and Mode Selection */
+	tc_ch0->TC_CMR =  TC_CMR_TCCLKS_XC0
+			| TC_CMR_ETRGEDG_RISING
+			| TC_CMR_ABETRG;
+
+	/* Enable QDEC in Position Mode*/
+	tc->TC_BMR =  TC_BMR_QDEN
+		    | TC_BMR_POSEN
+		    | TC_BMR_EDGPHA
+		    | TC_BMR_MAXFILT(1);
+
+	qdec_sam_start(tc);
+}
+
+static int qdec_sam_initialize(const struct device *dev)
+{
+	__ASSERT_NO_MSG(dev != NULL);
+	const struct qdec_sam_dev_cfg *const dev_cfg = DEV_CFG(dev);
+
+	/* Connect pins to the peripheral */
+	soc_gpio_list_configure(dev_cfg->pin_list, dev_cfg->pin_list_size);
+
+	for (int i = 0; i < ARRAY_SIZE(dev_cfg->periph_id); i++) {
+		/* Enable module's clock */
+		soc_pmc_peripheral_enable(dev_cfg->periph_id[i]);
+	}
+
+	qdec_sam_configure(dev);
+
+	LOG_INF("Device %s initialized", DEV_NAME(dev));
+
+	return 0;
+}
+
+static const struct sensor_driver_api qdec_sam_driver_api = {
+	.sample_fetch = qdec_sam_fetch,
+	.channel_get = qdec_sam_get,
+};
+
+#define QDEC_SAM_INIT(n)						\
+	static const struct soc_gpio_pin pins_tc##n[] = ATMEL_SAM_DT_PINS(n); \
+									\
+	static const struct qdec_sam_dev_cfg qdec##n##_sam_config = {	\
+		.regs = (Tc *)DT_INST_REG_ADDR(n),			\
+		.pin_list = pins_tc##n,					\
+		.pin_list_size = ARRAY_SIZE(pins_tc##n),		\
+		.periph_id = DT_INST_PROP(n, peripheral_id),		\
+	};								\
+									\
+	static struct qdec_sam_dev_data qdec##n##_sam_data;		\
+									\
+	DEVICE_DT_INST_DEFINE(n, qdec_sam_initialize, device_pm_control_nop, \
+			    &qdec##n##_sam_data, &qdec##n##_sam_config, \
+			    POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,	\
+			    &qdec_sam_driver_api);
+
+DT_INST_FOREACH_STATUS_OKAY(QDEC_SAM_INIT)
diff --git a/drivers/watchdog/wdt_npcx.c b/drivers/watchdog/wdt_npcx.c
index 4944e8140c5d5e18418857bca01637a6522e1427..3ff7c25be34762fdb6ef037bb72ffa42f18535d7 100644
--- a/drivers/watchdog/wdt_npcx.c
+++ b/drivers/watchdog/wdt_npcx.c
@@ -88,7 +88,8 @@ static inline void wdt_t0out_reload(const struct device *dev)
 
 	key = irq_lock();
 	/* Reload and restart T0 timer */
-	inst->T0CSR |= BIT(NPCX_T0CSR_RST);
+	inst->T0CSR = (inst->T0CSR & ~BIT(NPCX_T0CSR_WDRST_STS)) |
+		      BIT(NPCX_T0CSR_RST);
 	/* Wait for timer is loaded and restart */
 	while (IS_BIT_SET(inst->T0CSR, NPCX_T0CSR_RST))
 		;
@@ -312,8 +313,8 @@ static int wdt_npcx_init(const struct device *dev)
 	inst->TWCFG = BIT(NPCX_TWCFG_WDSDME) | BIT(NPCX_TWCFG_WDCT0I);
 
 	/* Disable early touch functionality */
-	inst->T0CSR |= BIT(NPCX_T0CSR_TESDIS);
-
+	inst->T0CSR = (inst->T0CSR & ~BIT(NPCX_T0CSR_WDRST_STS)) |
+		      BIT(NPCX_T0CSR_TESDIS);
 	/*
 	 * Plan clock frequency of T0 timer and watchdog timer as below:
 	 * - T0 Timer freq is LFCLK/32 Hz
diff --git a/dts/arm/acsip/s76s.dtsi b/dts/arm/acsip/s76s.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..8881b5be125a9b9be9b403dd52e0287704014c21
--- /dev/null
+++ b/dts/arm/acsip/s76s.dtsi
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c)  2021 Dean Weiten <dmw@weiten.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#include <st/l0/stm32l073Xz.dtsi>
+#include <st/l0/stm32l073r(b-z)tx-pinctrl.dtsi>
+
+&spi2 {
+	/* SX1276 SPI communication */
+	pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>;
+	cs-gpios = <&gpiob 12 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	lora: sx1276@0 {
+		compatible = "semtech,sx1276";
+		reg = <0>;
+		label = "sx1276";
+		/* SX1276 nRESET */
+		reset-gpios = <&gpiob 10 GPIO_ACTIVE_LOW>;
+		dio-gpios =
+			/* SX1276 D0 */
+			<&gpiob 11 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+			/* SX1276 D1 */
+			<&gpioc 13 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+			/* SX1276 D2 */
+			<&gpiob 9 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+			/* SX1276 D3 */
+			<&gpiob 4 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+			/* SX1276 D4 */
+			<&gpiob 3 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>,
+			/* SX1276 D5 */
+			<&gpioa 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
+		spi-max-frequency = <1000000>;
+		power-amplifier-output = "pa-boost";
+	};
+};
+
diff --git a/dts/arm/atmel/same70-pinctrl.dtsi b/dts/arm/atmel/same70-pinctrl.dtsi
index 9070a858a8fa804f40d2b757f473cd6816f31035..90d9423cfdbe0972fd220cde00f076896f8d77cd 100644
--- a/dts/arm/atmel/same70-pinctrl.dtsi
+++ b/dts/arm/atmel/same70-pinctrl.dtsi
@@ -108,6 +108,42 @@
 			DT_ATMEL_PIN(usart2, rxd2, d, 15, b);
 			DT_ATMEL_PIN(usart2, sck2, d, 17, b);
 			DT_ATMEL_PIN(usart2, txd2, d, 16, b);
+			DT_ATMEL_PIN(tc0, tclk0, a, 4, b);
+			DT_ATMEL_PIN(tc0, tclk1, a, 28, b);
+			DT_ATMEL_PIN(tc0, tclk2, a, 29, b);
+			DT_ATMEL_PIN(tc0, tioa0, a, 0, b);
+			DT_ATMEL_PIN(tc0, tioa1, a, 15, b);
+			DT_ATMEL_PIN(tc0, tioa2, a, 26, b);
+			DT_ATMEL_PIN(tc0, tiob0, a, 1, b);
+			DT_ATMEL_PIN(tc0, tiob1, a, 16, b);
+			DT_ATMEL_PIN(tc0, tiob2, a, 27, b);
+			DT_ATMEL_PIN(tc1, tclk3, c, 25, b);
+			DT_ATMEL_PIN(tc1, tclk4, c, 28, b);
+			DT_ATMEL_PIN(tc1, tclk5, c, 31, b);
+			DT_ATMEL_PIN(tc1, tioa3, c, 23, b);
+			DT_ATMEL_PIN(tc1, tioa4, c, 26, b);
+			DT_ATMEL_PIN(tc1, tioa5, c, 29, b);
+			DT_ATMEL_PIN(tc1, tiob3, c, 24, b);
+			DT_ATMEL_PIN(tc1, tiob4, c, 27, b);
+			DT_ATMEL_PIN(tc1, tiob5, c, 30, b);
+			DT_ATMEL_PIN(tc2, tclk6, c, 7, b);
+			DT_ATMEL_PIN(tc2, tclk7, c, 10, b);
+			DT_ATMEL_PIN(tc2, tclk8, c, 14, b);
+			DT_ATMEL_PIN(tc2, tioa6, c, 5, b);
+			DT_ATMEL_PIN(tc2, tioa7, c, 8, b);
+			DT_ATMEL_PIN(tc2, tioa8, c, 11, b);
+			DT_ATMEL_PIN(tc2, tiob6, c, 6, b);
+			DT_ATMEL_PIN(tc2, tiob7, c, 9, b);
+			DT_ATMEL_PIN(tc2, tiob8, c, 12, b);
+			DT_ATMEL_PIN(tc3, tclk9, e, 2, b);
+			DT_ATMEL_PIN(tc3, tclk10, e, 5, b);
+			DT_ATMEL_PIN(tc3, tclk11, d, 24, c);
+			DT_ATMEL_PIN(tc3, tioa9, e, 0, b);
+			DT_ATMEL_PIN(tc3, tioa10, e, 3, b);
+			DT_ATMEL_PIN(tc3, tioa11, d, 21, c);
+			DT_ATMEL_PIN(tc3, tiob9, e, 1, b);
+			DT_ATMEL_PIN(tc3, tiob10, e, 4, b);
+			DT_ATMEL_PIN(tc3, tiob11, d, 22, c);
 		};
 	};
 };
diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi
index 0fb175ed551c720b9f71cf226c166221dec1bbe1..002cf0ad383c173eecc3a21fb3b70a0315678277 100644
--- a/dts/arm/atmel/same70.dtsi
+++ b/dts/arm/atmel/same70.dtsi
@@ -355,6 +355,50 @@
 				     &pd8a_gmac_gmdc &pd9a_gmac_gmdio>;
 		};
 
+		tc0: tc@4000C000 {
+			compatible = "atmel,sam-tc";
+			reg = <0x4000C000 0x100>;
+			interrupts = <23 0
+				      24 0
+				      25 0>;
+			peripheral-id = <23 24 25>;
+			status = "disabled";
+			label = "TC0";
+		};
+
+		tc1: tc@40010000 {
+			compatible = "atmel,sam-tc";
+			reg = <0x40010000 0x100>;
+			interrupts = <26 0
+				      27 0
+				      28 0>;
+			peripheral-id = <26 27 28>;
+			status = "disabled";
+			label = "TC1";
+		};
+
+		tc2: tc@40014000 {
+			compatible = "atmel,sam-tc";
+			reg = <0x40014000 0x100>;
+			interrupts = <47 0
+				      48 0
+				      49 0>;
+			peripheral-id = <47 48 49>;
+			status = "disabled";
+			label = "TC2";
+		};
+
+		tc3: tc@40054000 {
+			compatible = "atmel,sam-tc";
+			reg = <0x40054000 0x100>;
+			interrupts = <50 0
+				      51 0
+				      52 0>;
+			peripheral-id = <50 51 52>;
+			status = "disabled";
+			label = "TC3";
+		};
+
 		trng: random@40070000 {
 			compatible = "atmel,sam-trng";
 			reg = <0x40070000 0x4000>;
diff --git a/dts/arm/nuvoton/npcx7.dtsi b/dts/arm/nuvoton/npcx7.dtsi
index 4d4585dd21e3f26e07b0699b3452cefe8ad1d3ee..6b9d1a043c7d56db7b584a7862e685c8f825edd3 100644
--- a/dts/arm/nuvoton/npcx7.dtsi
+++ b/dts/arm/nuvoton/npcx7.dtsi
@@ -121,8 +121,8 @@
 			label = "PMC_CDCG";
 		};
 
-		scfg: pin-controller@400c3000 {
-			compatible = "nuvoton,npcx-pinctrl";
+		scfg: scfg@400c3000 {
+			compatible = "nuvoton,npcx-scfg";
 			/* First reg region is System Configuration Device */
 			/* Second reg region is System Glue Device */
 			reg = <0x400c3000 0x70
diff --git a/dts/arm/silabs/efr32bg13p632f512gm48.dtsi b/dts/arm/silabs/efr32bg13p632f512gm48.dtsi
index 8a1bd1cd2f0ca8af6248a4ec133a48730c136471..fcc1b1a385d317d65fd35b992e49cf7622207309 100644
--- a/dts/arm/silabs/efr32bg13p632f512gm48.dtsi
+++ b/dts/arm/silabs/efr32bg13p632f512gm48.dtsi
@@ -5,7 +5,7 @@
  */
 
 #include <mem.h>
-#include <silabs/efr32bg13p.dtsi>
+#include <silabs/efr32xg13p.dtsi>
 
 / {
 	sram0: memory@20000000 {
@@ -13,7 +13,8 @@
 	};
 
 	soc {
-		compatible = "silabs,efr32bg13p632f512gm48", "silabs,efr32bg13p", "silabs,efr32", "simple-bus";
+		compatible = "silabs,efr32bg13p632f512gm48", "silabs,efr32xg13p",
+					 "silabs,efr32", "simple-bus";
 
 		flash-controller@400e0000 {
 			flash0: flash@0 {
diff --git a/dts/arm/silabs/efr32fg13p233f512gm48.dtsi b/dts/arm/silabs/efr32fg13p233f512gm48.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..b09875212aa8199cfc9d2fa6ba892f89098f69d2
--- /dev/null
+++ b/dts/arm/silabs/efr32fg13p233f512gm48.dtsi
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Linaro Limited
+ * Copyright (c) 2021 Yonatan Schachter
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <mem.h>
+#include <silabs/efr32xg13p.dtsi>
+
+/ {
+	sram0: memory@20000000 {
+		reg = <0x20000000 DT_SIZE_K(64)>;
+	};
+
+	soc {
+		compatible = "silabs,efr32fg13p233f512gm48", "silabs,efr32xg13p",
+					 "silabs,efr32", "simple-bus";
+
+		flash-controller@400e0000 {
+			flash0: flash@0 {
+				reg = <0 DT_SIZE_K(512)>;
+			};
+		};
+	};
+};
diff --git a/dts/arm/silabs/efr32bg13p.dtsi b/dts/arm/silabs/efr32xg13p.dtsi
similarity index 100%
rename from dts/arm/silabs/efr32bg13p.dtsi
rename to dts/arm/silabs/efr32xg13p.dtsi
diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi
index 11f77a3c6aeab36a25d9e5f391421222158a8c29..66e4ec3ef6327cfda8cb32f8695fb9856514a4fd 100644
--- a/dts/arm/st/f7/stm32f7.dtsi
+++ b/dts/arm/st/f7/stm32f7.dtsi
@@ -649,6 +649,15 @@
 			#io-channel-cells = <1>;
 		};
 
+		dac1: dac@40007400 {
+			compatible = "st,stm32-dac";
+			reg = <0x40007400 0x400>;
+			clocks = <&rcc STM32_CLOCK_BUS_APB1 0x20000000>;
+			status = "disabled";
+			label = "DAC_1";
+			#io-channel-cells = <1>;
+		};
+
 		dma1: dma@40026000 {
 			compatible = "st,stm32-dma-v1";
 			#dma-cells = <4>;
diff --git a/dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml b/dts/bindings/pinctrl/nuvoton,npcx-scfg.yaml
similarity index 83%
rename from dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml
rename to dts/bindings/pinctrl/nuvoton,npcx-scfg.yaml
index 13872e6b71194c2ed247cdc400d8c46d1f60c646..97aa33ca550833a1ff0f1efd4e90d540b75386b5 100644
--- a/dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml
+++ b/dts/bindings/pinctrl/nuvoton,npcx-scfg.yaml
@@ -1,9 +1,9 @@
 # Copyright (c) 2020 Nuvoton Technology Corporation.
 # SPDX-License-Identifier: Apache-2.0
 
-description: Nuvoton, NPCX Pin-Controller (Pinmux, 1.8V support and so on) node
+description: Nuvoton, NPCX System Configuration (Pinmux, 1.8V support and so on) node
 
-compatible: "nuvoton,npcx-pinctrl"
+compatible: "nuvoton,npcx-scfg"
 
 include: [base.yaml]
 
diff --git a/dts/bindings/timer/atmel,sam-tc.yaml b/dts/bindings/timer/atmel,sam-tc.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cc12a6626ac6e2eee5743fa509c6d59191eda4aa
--- /dev/null
+++ b/dts/bindings/timer/atmel,sam-tc.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: Apache-2.0
+
+description: Atmel SAM Timer Counter (TC) node
+
+compatible: "atmel,sam-tc"
+
+include: base.yaml
+
+properties:
+    reg:
+      required: true
+
+    interrupts:
+      required: true
+
+    label:
+      required: true
+
+    peripheral-id:
+      type: array
+      description: peripheral ID
+      required: true
+
+    pinctrl-0:
+      type: phandles
+      required: false
+      description: |
+        PIO pin configuration for Timer Counter signals.  We expect that
+        the phandles will reference pinctrl nodes.  These nodes will
+        have a nodelabel that matches the Atmel SoC HAL defines and
+        be of the form p<port><pin><periph>_<inst>_<signal>.
+
+        In Quadrature Decoder mode TIOA0 & TIOB0 signals are expected
+
+        For example the TC0 on SAME7x would be
+           pinctrl-0 = <&pa0b_tc0_tioa0 &pa1b_tc0_tiob0>;
diff --git a/include/app_memory/mem_domain.h b/include/app_memory/mem_domain.h
index e188e18ab86f3ba24c9560f1df2ddc5a62c2987c..0c52df36fd4003a556f9633146dea57458011048 100644
--- a/include/app_memory/mem_domain.h
+++ b/include/app_memory/mem_domain.h
@@ -124,20 +124,6 @@ struct k_mem_partition;
  */
 extern void k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
 			      struct k_mem_partition *parts[]);
-/**
- * @brief Destroy a memory domain.
- *
- * Destroy a memory domain. All member threads will be re-assigned to the
- * default memory domain.
- *
- * The default memory domain may not be destroyed.
- *
- * This API is deprecated and will be removed in Zephyr 2.5.
- *
- * @param domain The memory domain to be destroyed.
- */
-__deprecated
-extern void k_mem_domain_destroy(struct k_mem_domain *domain);
 
 /**
  * @brief Add a memory partition into a memory domain.
@@ -189,17 +175,6 @@ extern void k_mem_domain_remove_partition(struct k_mem_domain *domain,
 extern void k_mem_domain_add_thread(struct k_mem_domain *domain,
 				    k_tid_t thread);
 
-/**
- * @brief Remove a thread from its memory domain.
- *
- * Remove a thread from its memory domain. It will be reassigned to the
- * default memory domain.
- *
- * @param thread ID of thread going to be removed from its memory domain.
- */
-__deprecated
-extern void k_mem_domain_remove_thread(k_tid_t thread);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/arch/arc/v2/linker.ld b/include/arch/arc/v2/linker.ld
index e82e45288a145a1485279aeec5050ec660ff074b..e5398952529030acd25a554cf2f1c03e91870c18 100644
--- a/include/arch/arc/v2/linker.ld
+++ b/include/arch/arc/v2/linker.ld
@@ -101,8 +101,6 @@ SECTIONS {
 #include <linker/thread-local-storage.ld>
 
 	SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) {
-		KEEP(*(.openocd_dbg))
-		KEEP(*(".openocd_dbg.*"))
 		*(".rodata")
 		*(".rodata.*")
 		*(.gnu.linkonce.r.*)
diff --git a/include/arch/arm/aarch64/arm_mmu.h b/include/arch/arm/aarch64/arm_mmu.h
index b24454d06e466deab407263e7e27fccc2fbe51a9..9e86bccac9f119f949be0650fa2de01ef8d761fa 100644
--- a/include/arch/arm/aarch64/arm_mmu.h
+++ b/include/arch/arm/aarch64/arm_mmu.h
@@ -194,7 +194,11 @@ struct arm_mmu_ptables {
  */
 extern const struct arm_mmu_config mmu_config;
 
+struct k_thread;
 void z_arm64_mmu_init(void);
+void z_arm64_thread_pt_init(struct k_thread *thread);
+void z_arm64_swap_ptables(struct k_thread *thread);
+
 #endif /* _ASMLANGUAGE */
 
 #endif /* ZEPHYR_INCLUDE_ARCH_ARM64_MMU_ARM_MMU_H_ */
diff --git a/include/arch/arm/aarch64/scripts/linker.ld b/include/arch/arm/aarch64/scripts/linker.ld
index ea08bc960f9baa78d3668164471f63e3455ff17d..8c830dfc343d3741ff8ed4437d8364c4b45a0b1f 100644
--- a/include/arch/arm/aarch64/scripts/linker.ld
+++ b/include/arch/arm/aarch64/scripts/linker.ld
@@ -162,9 +162,6 @@ SECTIONS
     {
         KEEP(*(_IRQ_VECTOR_TABLE_SECTION_SYMS))
 
-        KEEP(*(.openocd_dbg))
-        KEEP(*(".openocd_dbg.*"))
-
         *(.rodata)
         *(".rodata.*")
         *(.gnu.linkonce.r.*)
diff --git a/include/arch/nios2/linker.ld b/include/arch/nios2/linker.ld
index f71e36dfe8043222b9d5cc099db3c23eb52821c9..71e1608826ddc7f2b0655cb7b877b60a86027613 100644
--- a/include/arch/nios2/linker.ld
+++ b/include/arch/nios2/linker.ld
@@ -124,8 +124,6 @@ SECTIONS
         *(.text)
         *(".text.*")
         *(.gnu.linkonce.t.*)
-        KEEP(*(.openocd_dbg))
-        KEEP(*(".openocd_dbg.*"))
         } GROUP_LINK_IN(ROMABLE_REGION)
 
     _image_text_end = .;
diff --git a/include/arch/x86/ia32/linker.ld b/include/arch/x86/ia32/linker.ld
index 898f5a0390c7ccff386e914177734db54220d366..1864b5b310b16133e56b18bf6703cbe93d9ded79 100644
--- a/include/arch/x86/ia32/linker.ld
+++ b/include/arch/x86/ia32/linker.ld
@@ -119,8 +119,6 @@ SECTIONS
 	*(.init)
 	*(.fini)
 	*(.eini)
-	KEEP(*(.openocd_dbg))
-	KEEP(*(".openocd_dbg.*"))
 
 #include <linker/kobject-text.ld>
 
diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h
index 3f74e4c60d4704482a2b494c2655bafa1e4f3397..09b9a2fb3b1460a7cdfb54aea6b2b1ec38ec5b35 100644
--- a/include/bluetooth/conn.h
+++ b/include/bluetooth/conn.h
@@ -600,6 +600,9 @@ struct bt_conn_le_create_param {
  *
  *  This uses the General Connection Establishment procedure.
  *
+ *  The application must disable explicit scanning before initiating
+ *  a new LE connection.
+ *
  *  @param[in]  peer         Remote address.
  *  @param[in]  create_param Create connection parameters.
  *  @param[in]  conn_param   Initial connection parameters.
diff --git a/include/devicetree/dma.h b/include/devicetree/dma.h
index 042eaa41314999a9c32e2c2b63b35df1a9ac7035..31e88e909f1efca2d8a5bcea9f13c9845461fd83 100644
--- a/include/devicetree/dma.h
+++ b/include/devicetree/dma.h
@@ -53,6 +53,7 @@ extern "C" {
  * @return the label property of the node referenced at index "idx"
  */
 #define DT_DMAS_LABEL_BY_IDX(node_id, idx) \
+	__DEPRECATED_MACRO \
 	DT_PROP_BY_PHANDLE_IDX(node_id, dmas, idx, label)
 
 /**
@@ -64,6 +65,7 @@ extern "C" {
  * @see DT_DMAS_LABEL_BY_IDX()
  */
 #define DT_INST_DMAS_LABEL_BY_IDX(inst, idx) \
+	__DEPRECATED_MACRO \
 	DT_DMAS_LABEL_BY_IDX(DT_DRV_INST(inst), idx)
 
 /**
@@ -99,6 +101,7 @@ extern "C" {
  * @return the label property of the node referenced at the named element
  */
 #define DT_DMAS_LABEL_BY_NAME(node_id, name) \
+	__DEPRECATED_MACRO \
 	DT_PROP(DT_PHANDLE_BY_NAME(node_id, dmas, name), label)
 
 /**
@@ -178,6 +181,7 @@ extern "C" {
  * @see DT_DMAS_LABEL_BY_NAME()
  */
 #define DT_INST_DMAS_LABEL_BY_NAME(inst, name) \
+	__DEPRECATED_MACRO \
 	DT_DMAS_LABEL_BY_NAME(DT_DRV_INST(inst), name)
 
 /**
diff --git a/include/drivers/counter.h b/include/drivers/counter.h
index b47e305cc5a0b0341e6ad7880ce4c63117007ef1..b649b303b0c39f36220c865e08c0df8dc50bd6f3 100644
--- a/include/drivers/counter.h
+++ b/include/drivers/counter.h
@@ -183,7 +183,6 @@ typedef int (*counter_api_set_top_value)(const struct device *dev,
 					 const struct counter_top_cfg *cfg);
 typedef uint32_t (*counter_api_get_pending_int)(const struct device *dev);
 typedef uint32_t (*counter_api_get_top_value)(const struct device *dev);
-typedef uint32_t (*counter_api_get_max_relative_alarm)(const struct device *dev);
 typedef uint32_t (*counter_api_get_guard_period)(const struct device *dev,
 						 uint32_t flags);
 typedef int (*counter_api_set_guard_period)(const struct device *dev,
@@ -199,7 +198,6 @@ __subsystem struct counter_driver_api {
 	counter_api_set_top_value set_top_value;
 	counter_api_get_pending_int get_pending_int;
 	counter_api_get_top_value get_top_value;
-	counter_api_get_max_relative_alarm get_max_relative_alarm;
 	counter_api_get_guard_period get_guard_period;
 	counter_api_set_guard_period set_guard_period;
 };
@@ -515,24 +513,6 @@ static inline uint32_t z_impl_counter_get_top_value(const struct device *dev)
 	return api->get_top_value(dev);
 }
 
-/**
- * @brief Function to retrieve maximum relative value that can be set by @ref
- *        counter_set_channel_alarm.
- *
- * @param[in]  dev    Pointer to the device structure for the driver instance.
- *
- * @return Max alarm value.
- */
-__deprecated __syscall uint32_t counter_get_max_relative_alarm(const struct device *dev);
-
-static inline uint32_t z_impl_counter_get_max_relative_alarm(const struct device *dev)
-{
-	const struct counter_driver_api *api =
-				(struct counter_driver_api *)dev->api;
-
-	return api->get_max_relative_alarm(dev);
-}
-
 /**
  * @brief Set guard period in counter ticks.
  *
@@ -601,21 +581,6 @@ static inline uint32_t z_impl_counter_get_guard_period(const struct device *dev,
 	return (api->get_guard_period) ? api->get_guard_period(dev, flags) : 0;
 }
 
-/* Deprecated counter callback. */
-typedef void (*counter_callback_t)(const struct device *dev, void *user_data);
-
-/* Deprecated counter read function. Use counter_get_value() instead. */
-__deprecated static inline uint32_t counter_read(const struct device *dev)
-{
-	uint32_t ticks;
-
-	if (counter_get_value(dev, &ticks) == 0) {
-		return ticks;
-	}
-
-	return 0;
-}
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld
index fd430ce8a0393a9cfe0bb6f1fd6cb50b313c4ed6..845ec703882ba437b65679d5eb3322524e476754 100644
--- a/include/linker/common-rom.ld
+++ b/include/linker/common-rom.ld
@@ -185,6 +185,11 @@
 
 	Z_ITERABLE_SECTION_ROM(tracing_backend, 4)
 
+	SECTION_DATA_PROLOGUE(zephyr_dbg_info,,)
+	{
+		KEEP(*(".dbg_thread_info"));
+	} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
+
 	SECTION_DATA_PROLOGUE(device_handles,,)
 	{
 		__device_handles_start = .;
diff --git a/include/net/net_if.h b/include/net/net_if.h
index ebf6a5ecbf20dc613ae174191f7e82afd9c4ff4f..07e32d26247eced56c1ad2cf2523b5aaafc8834f 100644
--- a/include/net/net_if.h
+++ b/include/net/net_if.h
@@ -627,6 +627,8 @@ static inline struct net_offload *net_if_offload(struct net_if *iface)
 #if defined(CONFIG_NET_OFFLOAD)
 	return iface->if_dev->offload;
 #else
+	ARG_UNUSED(iface);
+
 	return NULL;
 #endif
 }
@@ -709,6 +711,30 @@ static inline void net_if_stop_rs(struct net_if *iface)
 }
 #endif /* CONFIG_NET_IPV6_ND */
 
+/** @cond INTERNAL_HIDDEN */
+
+static inline int net_if_set_link_addr_unlocked(struct net_if *iface,
+						uint8_t *addr, uint8_t len,
+						enum net_link_type type)
+{
+	if (net_if_flag_is_set(iface, NET_IF_UP)) {
+		return -EPERM;
+	}
+
+	net_if_get_link_addr(iface)->addr = addr;
+	net_if_get_link_addr(iface)->len = len;
+	net_if_get_link_addr(iface)->type = type;
+
+	net_hostname_set_postfix(addr, len);
+
+	return 0;
+}
+
+int net_if_set_link_addr_locked(struct net_if *iface,
+				uint8_t *addr, uint8_t len,
+				enum net_link_type type);
+/** @endcond */
+
 /**
  * @brief Set a network interface's link address
  *
@@ -724,17 +750,11 @@ static inline int net_if_set_link_addr(struct net_if *iface,
 				       uint8_t *addr, uint8_t len,
 				       enum net_link_type type)
 {
-	if (net_if_flag_is_set(iface, NET_IF_UP)) {
-		return -EPERM;
-	}
-
-	net_if_get_link_addr(iface)->addr = addr;
-	net_if_get_link_addr(iface)->len = len;
-	net_if_get_link_addr(iface)->type = type;
-
-	net_hostname_set_postfix(addr, len);
-
-	return 0;
+#if defined(CONFIG_NET_RAW_MODE)
+	return net_if_set_link_addr_unlocked(iface, addr, len, type);
+#else
+	return net_if_set_link_addr_locked(iface, addr, len, type);
+#endif
 }
 
 /**
@@ -808,12 +828,7 @@ static inline struct net_if_config *net_if_config_get(struct net_if *iface)
  *
  * @param router Pointer to existing router
  */
-static inline void net_if_router_rm(struct net_if_router *router)
-{
-	router->is_used = false;
-
-	/* FIXME - remove timer */
-}
+void net_if_router_rm(struct net_if_router *router);
 
 /**
  * @brief Get the default network interface.
@@ -1061,12 +1076,7 @@ void net_if_mcast_monitor(struct net_if *iface, const struct in6_addr *addr,
  *
  * @param addr IPv6 multicast address
  */
-static inline void net_if_ipv6_maddr_join(struct net_if_mcast_addr *addr)
-{
-	NET_ASSERT(addr);
-
-	addr->is_joined = true;
-}
+void net_if_ipv6_maddr_join(struct net_if_mcast_addr *addr);
 
 /**
  * @brief Check if given multicast address is joined or not.
@@ -1087,12 +1097,7 @@ static inline bool net_if_ipv6_maddr_is_joined(struct net_if_mcast_addr *addr)
  *
  * @param addr IPv6 multicast address
  */
-static inline void net_if_ipv6_maddr_leave(struct net_if_mcast_addr *addr)
-{
-	NET_ASSERT(addr);
-
-	addr->is_joined = false;
-}
+void net_if_ipv6_maddr_leave(struct net_if_mcast_addr *addr);
 
 /**
  * @brief Return prefix that corresponds to this IPv6 address.
diff --git a/include/sys/arch_interface.h b/include/sys/arch_interface.h
index 2f164a4b1ab72c89e25a97035722ff1053b1301b..61033601b37462b1ff7ecdd78e17932d430ac597 100644
--- a/include/sys/arch_interface.h
+++ b/include/sys/arch_interface.h
@@ -609,19 +609,6 @@ void arch_mem_domain_partition_remove(struct k_mem_domain *domain,
  */
 void arch_mem_domain_partition_add(struct k_mem_domain *domain,
 				   uint32_t partition_id);
-
-/**
- * @brief Remove the memory domain
- *
- * Architecture-specific hook to manage internal data structures or hardware
- * state when a memory domain has been destroyed.
- *
- * Thread assignments to the memory domain are only cleared after this function
- * runs.
- *
- * @param domain The memory domain structure which needs to be deleted.
- */
-void arch_mem_domain_destroy(struct k_mem_domain *domain);
 #endif /* CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API */
 
 /**
diff --git a/include/sys/cbprintf_internal.h b/include/sys/cbprintf_internal.h
index c5de3137de7e0fd40255db673ea21784149561b6..56c02c7972f1cb7e136179599966856e6c106630 100644
--- a/include/sys/cbprintf_internal.h
+++ b/include/sys/cbprintf_internal.h
@@ -7,6 +7,7 @@
 #ifndef ZEPHYR_INCLUDE_SYS_CBPRINTF_INTERNAL_H_
 #define ZEPHYR_INCLUDE_SYS_CBPRINTF_INTERNAL_H_
 
+#include <errno.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -100,9 +101,7 @@ extern "C" {
 /** @brief Get storage size for given argument.
  *
  * Floats are promoted to double so they use size of double, others int storage
- * or it's own storage size if it is bigger than int. Strings are stored in
- * the package with 1 byte header indicating if string is stored as pointer or
- * by value.
+ * or it's own storage size if it is bigger than int.
  *
  * @param x argument.
  *
@@ -112,11 +111,7 @@ extern "C" {
 	_Generic((v), \
 		float : sizeof(double), \
 		default : \
-			_Generic((v), \
-				void * : 0, \
-				default : \
-					sizeof((v)+0) \
-				) \
+			sizeof((v)+0) \
 		)
 
 /** @brief Promote and store argument in the buffer.
@@ -125,6 +120,26 @@ extern "C" {
  *
  * @param arg Argument.
  */
+#ifdef __sparc__
+static inline void cbprintf_wcpy(int *dst, int *src, uint32_t len)
+{
+	for (int i = 0; i < len; i++) {
+		dst[i] = src[i];
+	}
+}
+/* Sparc is expecting va_list to be packed but don't support unaligned access.*/
+#define Z_CBPRINTF_STORE_ARG(buf, arg) do {\
+	__auto_type _v = (arg) + 0; \
+	double _d = _Generic((arg) + 0, \
+			float : (arg) + 0, \
+			default : \
+				0.0); \
+	uint32_t _wsize = Z_CBPRINTF_ARG_SIZE(arg) / sizeof(int); \
+	cbprintf_wcpy((int *)buf, \
+		      (int *) _Generic((arg) + 0, float : &_d, default : &_v), \
+		      _wsize); \
+} while (0)
+#else /* __sparc__ */
 #define Z_CBPRINTF_STORE_ARG(buf, arg) \
 	*_Generic((arg) + 0, \
 		char : (int *)buf, \
@@ -142,6 +157,7 @@ extern "C" {
 		long double : (long double *)buf, \
 		default : \
 			(const void **)buf) = arg
+#endif
 
 /** @brief Return alignment needed for given argument.
  *
diff --git a/kernel/Kconfig b/kernel/Kconfig
index bad9515b77f52493c6125b431d0da00c5589da1f..ce53daf82c44f4300816e90225ade512a6a4c376 100644
--- a/kernel/Kconfig
+++ b/kernel/Kconfig
@@ -753,7 +753,6 @@ config ARCH_MEM_DOMAIN_SYNCHRONOUS_API
 	  arch_mem_domain_thread_remove
 	  arch_mem_domain_partition_remove
 	  arch_mem_domain_partition_add
-	  arch_mem_domain_destroy
 
 	  It's important to note that although supervisor threads can be
 	  members of memory domains, they have no implications on supervisor
diff --git a/kernel/mem_domain.c b/kernel/mem_domain.c
index dd0fb38b48a562658edd26c1d768a5b531e9cee6..9d8695eb7dd39ecaf69b116c8353a69259a3d5d4 100644
--- a/kernel/mem_domain.c
+++ b/kernel/mem_domain.c
@@ -267,39 +267,6 @@ void k_mem_domain_add_thread(struct k_mem_domain *domain, k_tid_t thread)
 	k_spin_unlock(&z_mem_domain_lock, key);
 }
 
-/* LCOV_EXCL_START */
-void k_mem_domain_remove_thread(k_tid_t thread)
-{
-	k_mem_domain_add_thread(&k_mem_domain_default, thread);
-}
-
-void k_mem_domain_destroy(struct k_mem_domain *domain)
-{
-	k_spinlock_key_t key;
-	sys_dnode_t *node, *next_node;
-
-	__ASSERT_NO_MSG(domain != NULL);
-	__ASSERT(domain != &k_mem_domain_default,
-		 "cannot destroy default domain");
-
-	key = k_spin_lock(&z_mem_domain_lock);
-
-#ifdef CONFIG_ARCH_MEM_DOMAIN_SYNCHRONOUS_API
-	arch_mem_domain_destroy(domain);
-#endif
-
-	SYS_DLIST_FOR_EACH_NODE_SAFE(&domain->mem_domain_q, node, next_node) {
-		struct k_thread *thread =
-			CONTAINER_OF(node, struct k_thread, mem_domain_info);
-
-		remove_thread_locked(thread);
-		add_thread_locked(&k_mem_domain_default, thread);
-	}
-
-	k_spin_unlock(&z_mem_domain_lock, key);
-}
-/* LCOV_EXCL_STOP */
-
 static int init_mem_domain_module(const struct device *arg)
 {
 	ARG_UNUSED(arg);
diff --git a/lib/os/heap-validate.c b/lib/os/heap-validate.c
index dffe2193386c2c9153be2300b86a7a2959aa3b78..e121dbb6bd7998a478553bced0ab4850be7457cc 100644
--- a/lib/os/heap-validate.c
+++ b/lib/os/heap-validate.c
@@ -17,9 +17,9 @@
  * running one and corrupting it. YMMV.
  */
 
-static size_t max_chunkid(struct z_heap *h)
+static chunkid_t max_chunkid(struct z_heap *h)
 {
-	return h->len - min_chunk_size(h);
+	return h->end_chunk - min_chunk_size(h);
 }
 
 #define VALIDATE(cond) do { if (!(cond)) { return false; } } while (0)
@@ -28,14 +28,14 @@ static bool in_bounds(struct z_heap *h, chunkid_t c)
 {
 	VALIDATE(c >= right_chunk(h, 0));
 	VALIDATE(c <= max_chunkid(h));
-	VALIDATE(chunk_size(h, c) < h->len);
+	VALIDATE(chunk_size(h, c) < h->end_chunk);
 	return true;
 }
 
 static bool valid_chunk(struct z_heap *h, chunkid_t c)
 {
 	VALIDATE(chunk_size(h, c) > 0);
-	VALIDATE(c + chunk_size(h, c) <= h->len);
+	VALIDATE(c + chunk_size(h, c) <= h->end_chunk);
 	VALIDATE(in_bounds(h, c));
 	VALIDATE(right_chunk(h, left_chunk(h, c)) == c);
 	VALIDATE(left_chunk(h, right_chunk(h, c)) == c);
@@ -85,7 +85,7 @@ bool sys_heap_validate(struct sys_heap *heap)
 			return false;
 		}
 	}
-	if (c != h->len) {
+	if (c != h->end_chunk) {
 		return false;  /* Should have exactly consumed the buffer */
 	}
 
@@ -93,7 +93,7 @@ bool sys_heap_validate(struct sys_heap *heap)
 	 * should be correct, and all chunk entries should point into
 	 * valid unused chunks.  Mark those chunks USED, temporarily.
 	 */
-	for (int b = 0; b <= bucket_idx(h, h->len); b++) {
+	for (int b = 0; b <= bucket_idx(h, h->end_chunk); b++) {
 		chunkid_t c0 = h->buckets[b].next;
 		uint32_t n = 0;
 
@@ -137,7 +137,7 @@ bool sys_heap_validate(struct sys_heap *heap)
 
 		set_chunk_used(h, c, solo_free_header(h, c));
 	}
-	if (c != h->len) {
+	if (c != h->end_chunk) {
 		return false;  /* Should have exactly consumed the buffer */
 	}
 
@@ -145,7 +145,7 @@ bool sys_heap_validate(struct sys_heap *heap)
 	 * pass caught all the blocks and that they now show UNUSED.
 	 * Mark them USED.
 	 */
-	for (int b = 0; b <= bucket_idx(h, h->len); b++) {
+	for (int b = 0; b <= bucket_idx(h, h->end_chunk); b++) {
 		chunkid_t c0 = h->buckets[b].next;
 		int n = 0;
 
@@ -318,18 +318,18 @@ void sys_heap_stress(void *(*alloc)(void *arg, size_t bytes),
  */
 void heap_print_info(struct z_heap *h, bool dump_chunks)
 {
-	int i, nb_buckets = bucket_idx(h, h->len) + 1;
+	int i, nb_buckets = bucket_idx(h, h->end_chunk) + 1;
 	size_t free_bytes, allocated_bytes, total, overhead;
 
 	printk("Heap at %p contains %d units in %d buckets\n\n",
-	       chunk_buf(h), h->len, nb_buckets);
+	       chunk_buf(h), h->end_chunk, nb_buckets);
 
 	printk("  bucket#    min units        total      largest      largest\n"
 	       "             threshold       chunks      (units)      (bytes)\n"
 	       "  -----------------------------------------------------------\n");
 	for (i = 0; i < nb_buckets; i++) {
 		chunkid_t first = h->buckets[i].next;
-		size_t largest = 0;
+		chunksz_t largest = 0;
 		int count = 0;
 
 		if (first) {
@@ -341,9 +341,9 @@ void heap_print_info(struct z_heap *h, bool dump_chunks)
 			} while (curr != first);
 		}
 		if (count) {
-			printk("%9d %12d %12d %12zd %12zd\n",
+			printk("%9d %12d %12d %12d %12zd\n",
 			       i, (1 << i) - 1 + min_chunk_size(h), count,
-			       largest, largest * CHUNK_UNIT - chunk_header_bytes(h));
+			       largest, chunksz_to_bytes(h, largest));
 		}
 	}
 
@@ -352,17 +352,15 @@ void heap_print_info(struct z_heap *h, bool dump_chunks)
 	}
 	free_bytes = allocated_bytes = 0;
 	for (chunkid_t c = 0; ; c = right_chunk(h, c)) {
-		if (c == 0 || c == h->len) {
+		if (c == 0 || c == h->end_chunk) {
 			/* those are always allocated for internal purposes */
 		} else if (chunk_used(h, c)) {
-			allocated_bytes += chunk_size(h, c) * CHUNK_UNIT
-						- chunk_header_bytes(h);
+			allocated_bytes += chunksz_to_bytes(h, chunk_size(h, c));
 		} else if (!solo_free_header(h, c)) {
-			free_bytes += chunk_size(h, c) * CHUNK_UNIT
-						- chunk_header_bytes(h);
+			free_bytes += chunksz_to_bytes(h, chunk_size(h, c));
 		}
 		if (dump_chunks) {
-			printk("chunk %4zd: [%c] size=%-4zd left=%-4zd right=%zd\n",
+			printk("chunk %4d: [%c] size=%-4d left=%-4d right=%d\n",
 			       c,
 			       chunk_used(h, c) ? '*'
 			       : solo_free_header(h, c) ? '.'
@@ -371,16 +369,13 @@ void heap_print_info(struct z_heap *h, bool dump_chunks)
 			       left_chunk(h, c),
 			       right_chunk(h, c));
 		}
-		if (c == h->len) {
+		if (c == h->end_chunk) {
 			break;
 		}
 	}
 
-	/*
-	 * The final chunk at h->len  is just a header serving as a end
-	 * marker. It is part of the overhead.
-	 */
-	total = h->len * CHUNK_UNIT + chunk_header_bytes(h);
+	/* The end marker chunk has a header. It is part of the overhead. */
+	total = h->end_chunk * CHUNK_UNIT + chunk_header_bytes(h);
 	overhead = total - free_bytes - allocated_bytes;
 	printk("\n%zd free bytes, %zd allocated bytes, overhead = %zd bytes (%zd.%zd%%)\n",
 	       free_bytes, allocated_bytes, overhead,
diff --git a/lib/os/heap.c b/lib/os/heap.c
index af45e18ee1d669ccc0d2900d0aeb8e7f5f8534a3..8f8774248ca54561d4b0dc43333c35df880632fd 100644
--- a/lib/os/heap.c
+++ b/lib/os/heap.c
@@ -13,7 +13,7 @@ static void *chunk_mem(struct z_heap *h, chunkid_t c)
 	chunk_unit_t *buf = chunk_buf(h);
 	uint8_t *ret = ((uint8_t *)&buf[c]) + chunk_header_bytes(h);
 
-	CHECK(!(((size_t)ret) & (big_heap(h) ? 7 : 3)));
+	CHECK(!(((uintptr_t)ret) & (big_heap(h) ? 7 : 3)));
 
 	return ret;
 }
@@ -90,9 +90,9 @@ static void split_chunks(struct z_heap *h, chunkid_t lc, chunkid_t rc)
 	CHECK(rc > lc);
 	CHECK(rc - lc < chunk_size(h, lc));
 
-	size_t sz0 = chunk_size(h, lc);
-	size_t lsz = rc - lc;
-	size_t rsz = sz0 - lsz;
+	chunksz_t sz0 = chunk_size(h, lc);
+	chunksz_t lsz = rc - lc;
+	chunksz_t rsz = sz0 - lsz;
 
 	set_chunk_size(h, lc, lsz);
 	set_chunk_size(h, rc, rsz);
@@ -103,7 +103,7 @@ static void split_chunks(struct z_heap *h, chunkid_t lc, chunkid_t rc)
 /* Does not modify free list */
 static void merge_chunks(struct z_heap *h, chunkid_t lc, chunkid_t rc)
 {
-	size_t newsz = chunk_size(h, lc) + chunk_size(h, rc);
+	chunksz_t newsz = chunk_size(h, lc) + chunk_size(h, rc);
 
 	set_chunk_size(h, lc, newsz);
 	set_left_chunk_size(h, right_chunk(h, rc), newsz);
@@ -167,14 +167,12 @@ void sys_heap_free(struct sys_heap *heap, void *mem)
 	free_chunk(h, c);
 }
 
-static chunkid_t alloc_chunk(struct z_heap *h, size_t sz)
+static chunkid_t alloc_chunk(struct z_heap *h, chunksz_t sz)
 {
 	int bi = bucket_idx(h, sz);
 	struct z_heap_bucket *b = &h->buckets[bi];
 
-	if (bi > bucket_idx(h, h->len)) {
-		return 0;
-	}
+	CHECK(bi <= bucket_idx(h, h->end_chunk));
 
 	/* First try a bounded count of items from the minimal bucket
 	 * size.  These may not fit, trying (e.g.) three means that
@@ -207,10 +205,10 @@ static chunkid_t alloc_chunk(struct z_heap *h, size_t sz)
 	/* Otherwise pick the smallest non-empty bucket guaranteed to
 	 * fit and use that unconditionally.
 	 */
-	size_t bmask = h->avail_buckets & ~((1 << (bi + 1)) - 1);
+	uint32_t bmask = h->avail_buckets & ~((1 << (bi + 1)) - 1);
 
-	if ((bmask & h->avail_buckets) != 0U) {
-		int minbucket = __builtin_ctz(bmask & h->avail_buckets);
+	if (bmask != 0U) {
+		int minbucket = __builtin_ctz(bmask);
 		chunkid_t c = h->buckets[minbucket].next;
 
 		free_list_remove_bidx(h, c, minbucket);
@@ -229,7 +227,7 @@ void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)
 		return NULL;
 	}
 
-	size_t chunk_sz = bytes_to_chunksz(h, bytes);
+	chunksz_t chunk_sz = bytes_to_chunksz(h, bytes);
 	chunkid_t c = alloc_chunk(h, chunk_sz);
 	if (c == 0U) {
 		return NULL;
@@ -248,7 +246,7 @@ void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)
 void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
 {
 	struct z_heap *h = heap->heap;
-	size_t padded_sz, gap, rewind;
+	size_t gap, rewind;
 
 	/*
 	 * Split align and rewind values (if any).
@@ -279,7 +277,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
 	 * We over-allocate to account for alignment and then free
 	 * the extra allocations afterwards.
 	 */
-	padded_sz = bytes_to_chunksz(h, bytes + align - gap);
+	chunksz_t padded_sz = bytes_to_chunksz(h, bytes + align - gap);
 	chunkid_t c0 = alloc_chunk(h, padded_sz);
 
 	if (c0 == 0) {
@@ -335,7 +333,7 @@ void *sys_heap_aligned_realloc(struct sys_heap *heap, void *ptr,
 	chunkid_t c = mem_to_chunkid(h, ptr);
 	chunkid_t rc = right_chunk(h, c);
 	size_t align_gap = (uint8_t *)ptr - (uint8_t *)chunk_mem(h, c);
-	size_t chunks_need = bytes_to_chunksz(h, bytes + align_gap);
+	chunksz_t chunks_need = bytes_to_chunksz(h, bytes + align_gap);
 
 	if (align && ((uintptr_t)ptr & (align - 1))) {
 		/* ptr is not sufficiently aligned */
@@ -369,8 +367,7 @@ void *sys_heap_aligned_realloc(struct sys_heap *heap, void *ptr,
 	void *ptr2 = sys_heap_aligned_alloc(heap, align, bytes);
 
 	if (ptr2 != NULL) {
-		size_t prev_size = chunk_size(h, c) * CHUNK_UNIT
-				   - chunk_header_bytes(h) - align_gap;
+		size_t prev_size = chunksz_to_bytes(h, chunk_size(h, c)) - align_gap;
 
 		memcpy(ptr2, ptr, MIN(prev_size, bytes));
 		sys_heap_free(heap, ptr);
@@ -383,29 +380,28 @@ void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes)
 	/* Must fit in a 31 bit count of HUNK_UNIT */
 	__ASSERT(bytes / CHUNK_UNIT <= 0x7fffffffU, "heap size is too big");
 
-	/* Reserve the final marker chunk's header */
+	/* Reserve the end marker chunk's header */
 	__ASSERT(bytes > heap_footer_bytes(bytes), "heap size is too small");
 	bytes -= heap_footer_bytes(bytes);
 
 	/* Round the start up, the end down */
 	uintptr_t addr = ROUND_UP(mem, CHUNK_UNIT);
 	uintptr_t end = ROUND_DOWN((uint8_t *)mem + bytes, CHUNK_UNIT);
-	size_t buf_sz = (end - addr) / CHUNK_UNIT;
+	chunksz_t heap_sz = (end - addr) / CHUNK_UNIT;
 
 	CHECK(end > addr);
-	__ASSERT(buf_sz > chunksz(sizeof(struct z_heap)), "heap size is too small");
+	__ASSERT(heap_sz > chunksz(sizeof(struct z_heap)), "heap size is too small");
 
 	struct z_heap *h = (struct z_heap *)addr;
 	heap->heap = h;
-	h->chunk0_hdr_area = 0;
-	h->len = buf_sz;
+	h->end_chunk = heap_sz;
 	h->avail_buckets = 0;
 
-	int nb_buckets = bucket_idx(h, buf_sz) + 1;
-	size_t chunk0_size = chunksz(sizeof(struct z_heap) +
+	int nb_buckets = bucket_idx(h, heap_sz) + 1;
+	chunksz_t chunk0_size = chunksz(sizeof(struct z_heap) +
 				     nb_buckets * sizeof(struct z_heap_bucket));
 
-	__ASSERT(chunk0_size + min_chunk_size(h) < buf_sz, "heap size is too small");
+	__ASSERT(chunk0_size + min_chunk_size(h) < heap_sz, "heap size is too small");
 
 	for (int i = 0; i < nb_buckets; i++) {
 		h->buckets[i].next = 0;
@@ -413,16 +409,17 @@ void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes)
 
 	/* chunk containing our struct z_heap */
 	set_chunk_size(h, 0, chunk0_size);
+	set_left_chunk_size(h, 0, 0);
 	set_chunk_used(h, 0, true);
 
 	/* chunk containing the free heap */
-	set_chunk_size(h, chunk0_size, buf_sz - chunk0_size);
+	set_chunk_size(h, chunk0_size, heap_sz - chunk0_size);
 	set_left_chunk_size(h, chunk0_size, chunk0_size);
 
 	/* the end marker chunk */
-	set_chunk_size(h, buf_sz, 0);
-	set_left_chunk_size(h, buf_sz, buf_sz - chunk0_size);
-	set_chunk_used(h, buf_sz, true);
+	set_chunk_size(h, heap_sz, 0);
+	set_left_chunk_size(h, heap_sz, heap_sz - chunk0_size);
+	set_chunk_used(h, heap_sz, true);
 
 	free_list_add(h, chunk0_size);
 }
diff --git a/lib/os/heap.h b/lib/os/heap.h
index 5482189190691c2f53342a6319b8952d26ed0d75..6deaaec64364f2ba85c38c05a0189e765605d6ee 100644
--- a/lib/os/heap.h
+++ b/lib/os/heap.h
@@ -33,10 +33,10 @@
  * field accessors since we can't use natural syntax.
  *
  * The fields are:
- *   SIZE_AND_USED: the total size (including header) of the chunk in
- *                  8-byte units.  The bottom bit stores a "used" flag.
  *   LEFT_SIZE: The size of the left (next lower chunk in memory)
  *              neighbor chunk.
+ *   SIZE_AND_USED: the total size (including header) of the chunk in
+ *                  8-byte units.  The bottom bit stores a "used" flag.
  *   FREE_PREV: Chunk ID of the previous node in a free list.
  *   FREE_NEXT: Chunk ID of the next node in a free list.
  *
@@ -44,27 +44,35 @@
  * category.  The free list pointers exist only for free chunks,
  * obviously.  This memory is part of the user's buffer when
  * allocated.
+ *
+ * The field order is so that allocated buffers are immediately bounded
+ * by SIZE_AND_USED of the current chunk at the bottom, and LEFT_SIZE of
+ * the following chunk at the top. This ordering allows for quick buffer
+ * overflow detection by testing left_chunk(c + chunk_size(c)) == c.
  */
-typedef size_t chunkid_t;
+
+enum chunk_fields { LEFT_SIZE, SIZE_AND_USED, FREE_PREV, FREE_NEXT };
 
 #define CHUNK_UNIT 8U
 
 typedef struct { char bytes[CHUNK_UNIT]; } chunk_unit_t;
 
-enum chunk_fields { LEFT_SIZE, SIZE_AND_USED, FREE_PREV, FREE_NEXT };
+/* big_heap needs uint32_t, small_heap needs uint16_t */
+typedef uint32_t chunkid_t;
+typedef uint32_t chunksz_t;
 
 struct z_heap_bucket {
 	chunkid_t next;
 };
 
 struct z_heap {
-	uint64_t chunk0_hdr_area;  /* matches the largest header */
-	uint32_t len;
+	chunkid_t chunk0_hdr[2];
+	chunkid_t end_chunk;
 	uint32_t avail_buckets;
 	struct z_heap_bucket buckets[0];
 };
 
-static inline bool big_heap_chunks(size_t chunks)
+static inline bool big_heap_chunks(chunksz_t chunks)
 {
 	return sizeof(void *) > 4U || chunks > 0x7fffU;
 }
@@ -76,7 +84,7 @@ static inline bool big_heap_bytes(size_t bytes)
 
 static inline bool big_heap(struct z_heap *h)
 {
-	return big_heap_chunks(h->len);
+	return big_heap_chunks(h->end_chunk);
 }
 
 static inline chunk_unit_t *chunk_buf(struct z_heap *h)
@@ -85,8 +93,8 @@ static inline chunk_unit_t *chunk_buf(struct z_heap *h)
 	return (chunk_unit_t *)h;
 }
 
-static inline size_t chunk_field(struct z_heap *h, chunkid_t c,
-				 enum chunk_fields f)
+static inline chunkid_t chunk_field(struct z_heap *h, chunkid_t c,
+				    enum chunk_fields f)
 {
 	chunk_unit_t *buf = chunk_buf(h);
 	void *cmem = &buf[c];
@@ -101,7 +109,7 @@ static inline size_t chunk_field(struct z_heap *h, chunkid_t c,
 static inline void chunk_set(struct z_heap *h, chunkid_t c,
 			     enum chunk_fields f, chunkid_t val)
 {
-	CHECK(c <= h->len);
+	CHECK(c <= h->end_chunk);
 
 	chunk_unit_t *buf = chunk_buf(h);
 	void *cmem = &buf[c];
@@ -120,7 +128,7 @@ static inline bool chunk_used(struct z_heap *h, chunkid_t c)
 	return chunk_field(h, c, SIZE_AND_USED) & 1U;
 }
 
-static inline size_t chunk_size(struct z_heap *h, chunkid_t c)
+static inline chunksz_t chunk_size(struct z_heap *h, chunkid_t c)
 {
 	return chunk_field(h, c, SIZE_AND_USED) >> 1;
 }
@@ -150,7 +158,7 @@ static inline void set_chunk_used(struct z_heap *h, chunkid_t c, bool used)
  * when its size is modified, and potential set_chunk_used() is always
  * invoked after set_chunk_size().
  */
-static inline void set_chunk_size(struct z_heap *h, chunkid_t c, size_t size)
+static inline void set_chunk_size(struct z_heap *h, chunkid_t c, chunksz_t size)
 {
 	chunk_set(h, c, SIZE_AND_USED, size << 1);
 }
@@ -188,7 +196,7 @@ static inline chunkid_t right_chunk(struct z_heap *h, chunkid_t c)
 }
 
 static inline void set_left_chunk_size(struct z_heap *h, chunkid_t c,
-				       size_t size)
+				       chunksz_t size)
 {
 	chunk_set(h, c, LEFT_SIZE, size);
 }
@@ -208,24 +216,29 @@ static inline size_t heap_footer_bytes(size_t size)
 	return big_heap_bytes(size) ? 8 : 4;
 }
 
-static inline size_t chunksz(size_t bytes)
+static inline chunksz_t chunksz(size_t bytes)
 {
 	return (bytes + CHUNK_UNIT - 1U) / CHUNK_UNIT;
 }
 
-static inline size_t bytes_to_chunksz(struct z_heap *h, size_t bytes)
+static inline chunksz_t bytes_to_chunksz(struct z_heap *h, size_t bytes)
 {
 	return chunksz(chunk_header_bytes(h) + bytes);
 }
 
-static inline int min_chunk_size(struct z_heap *h)
+static inline chunksz_t min_chunk_size(struct z_heap *h)
 {
 	return bytes_to_chunksz(h, 1);
 }
 
-static inline int bucket_idx(struct z_heap *h, size_t sz)
+static inline size_t chunksz_to_bytes(struct z_heap *h, chunksz_t chunksz)
+{
+	return chunksz * CHUNK_UNIT - chunk_header_bytes(h);
+}
+
+static inline int bucket_idx(struct z_heap *h, chunksz_t sz)
 {
-	size_t usable_sz = sz - min_chunk_size(h) + 1;
+	unsigned int usable_sz = sz - min_chunk_size(h) + 1;
 	return 31 - __builtin_clz(usable_sz);
 }
 
@@ -234,9 +247,8 @@ static inline bool size_too_big(struct z_heap *h, size_t bytes)
 	/*
 	 * Quick check to bail out early if size is too big.
 	 * Also guards against potential arithmetic overflows elsewhere.
-	 * There is a minimum of one chunk always in use by the heap header.
 	 */
-	return (bytes / CHUNK_UNIT) >= h->len;
+	return (bytes / CHUNK_UNIT) >= h->end_chunk;
 }
 
 /* For debugging */
diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt
index b51944d6a0c8276ca282fb776fc02e6545c26954..b5b5880c3a87ee12fde8b0e0da6a0350b5f255c8 100644
--- a/modules/trusted-firmware-m/CMakeLists.txt
+++ b/modules/trusted-firmware-m/CMakeLists.txt
@@ -278,6 +278,14 @@ if (CONFIG_BUILD_WITH_TFM)
     set(TFM_PUBLIC_KEY_FORMAT "full")
   endif()
 
+  if(DEFINED TFM_HEX_BASE_ADDRESS_S)
+    set(HEX_ADDR_ARGS_S "--hex-addr=${TFM_HEX_BASE_ADDRESS_S}")
+  endif()
+
+  if(DEFINED TFM_HEX_BASE_ADDRESS_NS)
+    set(HEX_ADDR_ARGS_NS "--hex-addr=${TFM_HEX_BASE_ADDRESS_NS}")
+  endif()
+
   function(tfm_sign OUT_ARG SUFFIX PAD INPUT_FILE OUTPUT_FILE)
     if(PAD)
       set(pad_args --pad --pad-header)
@@ -290,6 +298,7 @@ if (CONFIG_BUILD_WITH_TFM)
       --align 1
       -v ${TFM_IMAGE_VERSION_${SUFFIX}}
       ${pad_args}
+      ${HEX_ADDR_ARGS_${SUFFIX}}
       ${ADD_${SUFFIX}_IMAGE_MIN_VER}
       -s auto
       -H ${CONFIG_ROM_START_OFFSET}
diff --git a/modules/trusted-firmware-m/Kconfig b/modules/trusted-firmware-m/Kconfig
index 097cf138ed03acc2af9a3248e4b30895436af65d..6530b4012688e57dbd8de6a868fe1ef1e6b434cb 100644
--- a/modules/trusted-firmware-m/Kconfig
+++ b/modules/trusted-firmware-m/Kconfig
@@ -14,6 +14,7 @@ config TFM_BOARD
 	default "nxp/lpcxpresso55s69" if BOARD_LPCXPRESSO55S69_CPU0
 	default "mps2/an521" if BOARD_MPS2_AN521
 	default "stm/nucleo_l552ze_q" if BOARD_NUCLEO_L552ZE_Q
+	default "stm/stm32l562e_dk" if BOARD_STM32L562E_DK
 	default "musca_b1" if BOARD_MUSCA_B1
 	default "musca_s1" if BOARD_MUSCA_S1
 	help
diff --git a/samples/bluetooth/bluetooth.rst b/samples/bluetooth/bluetooth.rst
index 88cbd10e6bb5caedfea8bad566070acbbe3680fd..03a1f05c9ab37cae3185a629d884ac6a6e0b8aa3 100644
--- a/samples/bluetooth/bluetooth.rst
+++ b/samples/bluetooth/bluetooth.rst
@@ -20,7 +20,7 @@ documentation and are prefixed with :literal:`hci_` in their folder names.
    ``-DBOARD=nrf5340dk_nrf5340_cpuapp`` or
    ``-DBOARD=nrf5340dk_nrf5340_cpuappns``) you must also build
    and program the corresponding sample for the nRF5340 network core
-   :ref:` bluetooth-hci-rpmsg-sample` which implements the Bluetooth
+   :ref:`bluetooth-hci-rpmsg-sample` which implements the Bluetooth
    Low Energy controller.
 
 .. note::
diff --git a/samples/drivers/dac/README.rst b/samples/drivers/dac/README.rst
index f5732e5d6b7b4575f35f0c9de51a70d9f1cb9c88..99478330c3b319ea50a1b5b08c92d56584b52ff7 100644
--- a/samples/drivers/dac/README.rst
+++ b/samples/drivers/dac/README.rst
@@ -35,6 +35,17 @@ The sample can be built and executed for the
    :goals: build flash
    :compact:
 
+Building and Running for ST Nucleo F767ZI
+=========================================
+The sample can be built and executed for the
+:ref:`nucleo_f767zi_board` as follows:
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/drivers/dac
+   :board: nucleo_f767zi
+   :goals: build flash
+   :compact:
+
 Building and Running for NXP TWR-KE18F
 ======================================
 The sample can be built and executed for the :ref:`twr_ke18f` as
diff --git a/samples/drivers/dac/sample.yaml b/samples/drivers/dac/sample.yaml
index efdcb9edc66cef9f3326e64bb242099fb28b6827..2c11cfdf0ad9e546a0295b9c46bd960cace35297 100644
--- a/samples/drivers/dac/sample.yaml
+++ b/samples/drivers/dac/sample.yaml
@@ -5,7 +5,7 @@ tests:
     tags: DAC
     platform_allow: |
       arduino_zero frdm_k22f frdm_k64f nucleo_f091rc nucleo_g071rb nucleo_g431rb
-      nucleo_l073rz nucleo_l152re twr_ke18f
+      nucleo_l073rz nucleo_l152re twr_ke18f nucleo_f767zi
     depends_on: dac
     harness: console
     harness_config:
diff --git a/samples/drivers/dac/src/main.c b/samples/drivers/dac/src/main.c
index 5ea128b413e21c8c6e158664f6f9b02d94a110b3..585c6f68b4d3aa1621a13939de0fcd17091c2035 100644
--- a/samples/drivers/dac/src/main.c
+++ b/samples/drivers/dac/src/main.c
@@ -12,7 +12,9 @@
 	defined(CONFIG_BOARD_NUCLEO_G071RB) || \
 	defined(CONFIG_BOARD_NUCLEO_G431RB) || \
 	defined(CONFIG_BOARD_NUCLEO_L073RZ) || \
-	defined(CONFIG_BOARD_NUCLEO_L152RE)
+	defined(CONFIG_BOARD_NUCLEO_L152RE) || \
+	defined(CONFIG_BOARD_NUCLEO_F767ZI) || \
+	defined(CONFIG_BOARD_RONOTH_LODEV)
 #define DAC_DEVICE_NAME		DT_LABEL(DT_NODELABEL(dac1))
 #define DAC_CHANNEL_ID		1
 #define DAC_RESOLUTION		12
diff --git a/samples/sensor/qdec/CMakeLists.txt b/samples/sensor/qdec/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fa78fa5e610c85ee9b04a5119acd52770506e32f
--- /dev/null
+++ b/samples/sensor/qdec/CMakeLists.txt
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(thermometer)
+
+FILE(GLOB app_sources src/*.c)
+target_sources(app PRIVATE ${app_sources})
diff --git a/samples/sensor/qdec/README.rst b/samples/sensor/qdec/README.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6b160475e34ae5f103ed70144b305736b797ee11
--- /dev/null
+++ b/samples/sensor/qdec/README.rst
@@ -0,0 +1,37 @@
+.. _qdec:
+
+QDEC: Quadrature Decoder
+###########################
+
+Overview
+********
+A simple quadrature decoder example
+
+Building and Running
+********************
+
+This project writes the quadrature decoder position to the console once every
+2 seconds.
+
+Building on SAM E70 Xplained board
+==================================
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/sensor/qdec
+   :host-os: unix
+   :board: sam_e70_xplained
+   :goals: build
+   :compact:
+
+Sample Output
+=============
+
+.. code-block:: console
+
+    Quadrature Decoder sample application
+
+    Position is 6
+    Position is 12
+    Position is -45
+
+    <repeats endlessly every 2 seconds>
diff --git a/samples/sensor/qdec/boards/sam_e70_xplained.conf b/samples/sensor/qdec/boards/sam_e70_xplained.conf
new file mode 100644
index 0000000000000000000000000000000000000000..1532e5c38993e0141183c83081ac0b117fb83224
--- /dev/null
+++ b/samples/sensor/qdec/boards/sam_e70_xplained.conf
@@ -0,0 +1 @@
+CONFIG_QDEC_SAM=y
diff --git a/samples/sensor/qdec/boards/sam_e70_xplained.overlay b/samples/sensor/qdec/boards/sam_e70_xplained.overlay
new file mode 100644
index 0000000000000000000000000000000000000000..1eda42483dc099ab0c48d7f700c5d2fee0ffd1cf
--- /dev/null
+++ b/samples/sensor/qdec/boards/sam_e70_xplained.overlay
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2021, Piotr Mienkowski
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+&tc0 {
+	status = "okay";
+	pinctrl-0 = <&pa0b_tc0_tioa0 &pa1b_tc0_tiob0>;
+	label = "QDEC_0";
+};
diff --git a/samples/sensor/qdec/prj.conf b/samples/sensor/qdec/prj.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2ee2ffb6e80138ba8d6cc7f1da29e63467ef315b
--- /dev/null
+++ b/samples/sensor/qdec/prj.conf
@@ -0,0 +1,2 @@
+CONFIG_SENSOR=y
+CONFIG_STDOUT_CONSOLE=y
diff --git a/samples/sensor/qdec/sample.yaml b/samples/sensor/qdec/sample.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a996a2f187a5de1a627f93c1486e6522dfe9b52c
--- /dev/null
+++ b/samples/sensor/qdec/sample.yaml
@@ -0,0 +1,7 @@
+sample:
+  name: Quadrature Decoder
+tests:
+  sample.sensor.qdec:
+    tags: sensors
+    harness: sensor
+    platform_allow: sam_e70_xplained
diff --git a/samples/sensor/qdec/src/main.c b/samples/sensor/qdec/src/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..d7d0ac219ba8482587906bd98d5f62bd398b8ee6
--- /dev/null
+++ b/samples/sensor/qdec/src/main.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021, Piotr Mienkowski
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <drivers/sensor.h>
+#include <stdio.h>
+
+void main(void)
+{
+	const struct device *dev;
+	int ret;
+
+	printf("Quadrature Decoder sample application\n\n");
+
+	dev = device_get_binding("QDEC_0");
+	if (!dev) {
+		printf("error: no QDEC_0 device\n");
+		return;
+	}
+
+	while (1) {
+		struct sensor_value value;
+
+		ret = sensor_sample_fetch(dev);
+		if (ret) {
+			printf("sensor_sample_fetch failed returns: %d\n", ret);
+			break;
+		}
+
+		ret = sensor_channel_get(dev, SENSOR_CHAN_ROTATION, &value);
+		if (ret) {
+			printf("sensor_channel_get failed returns: %d\n", ret);
+			break;
+		}
+
+		printf("Position is %d\n", value.val1);
+
+		k_sleep(K_MSEC(2000));
+	}
+}
diff --git a/samples/subsys/nvs/boards/esp32.conf b/samples/subsys/nvs/boards/esp32.conf
new file mode 100644
index 0000000000000000000000000000000000000000..26d52701286e555676f05aeccfdbab42874285c2
--- /dev/null
+++ b/samples/subsys/nvs/boards/esp32.conf
@@ -0,0 +1 @@
+CONFIG_HEAP_MEM_POOL_SIZE=256
diff --git a/samples/subsys/settings/boards/esp32.conf b/samples/subsys/settings/boards/esp32.conf
new file mode 100644
index 0000000000000000000000000000000000000000..498fb072287d63f26165bfb721faa124ac3d0379
--- /dev/null
+++ b/samples/subsys/settings/boards/esp32.conf
@@ -0,0 +1,4 @@
+CONFIG_HEAP_MEM_POOL_SIZE=256
+CONFIG_NVS=y
+CONFIG_SETTINGS_NVS=y
+CONFIG_MPU_ALLOW_FLASH_WRITE=y
diff --git a/samples/subsys/tracing/sample.yaml b/samples/subsys/tracing/sample.yaml
index fccefe3f68304c387f77c80375d34eb6abc37aa3..ef92547f861363ca2dee879f39868454c8c4bec7 100644
--- a/samples/subsys/tracing/sample.yaml
+++ b/samples/subsys/tracing/sample.yaml
@@ -18,7 +18,7 @@ tests:
   tracing.osawareness.openocd:
     extra_configs:
       - CONFIG_MP_NUM_CPUS=1
-      - CONFIG_OPENOCD_SUPPORT=y
+      - CONFIG_DEBUG_THREAD_INFO=y
       - CONFIG_SMP=n
     arch_exclude: posix xtensa
     platform_exclude: qemu_x86_64
diff --git a/samples/tfm_integration/tfm_ipc/README.rst b/samples/tfm_integration/tfm_ipc/README.rst
index b76255b3af0e88040c2d8485cca6497f61e2bb0d..848c63d3fe83c519e5130c92ce9cf565d6e4c3ad 100644
--- a/samples/tfm_integration/tfm_ipc/README.rst
+++ b/samples/tfm_integration/tfm_ipc/README.rst
@@ -103,33 +103,38 @@ Or, post build:
 
       $ ninja run
 
-On ST Nucleo L552ZE Q:
-======================
+On ST Nucleo L552ZE Q or STM32L562E-DK Discovery:
+=================================================
 
 This sample was tested on Ubuntu 18.04 with Zephyr SDK 0.11.3.
 
 Build Zephyr with a non-secure configuration:
 
+   Example, for building non-secure configuration for Nucleo L552ZE Q
+
    .. code-block:: bash
 
       $ west build -b nucleo_l552ze_q_ns samples/tfm_integration/tfm_ipc/
 
-Two scripts are avalaible in the ``build/tfm`` folder:
+   Example, for building non-secure configuration for STM32L562E-DK Discovery
+
+   .. code-block:: bash
+
+      $ west build -b stm32l562e_dk_ns samples/tfm_integration/tfm_ipc/
+
+The script to initialize the device is avalaible in the ``build/tfm`` folder:
 
   - ``regression.sh``: Sets platform option bytes config and erase platform.
-  - ``TFM_UPDATE.sh``: Writes bl2, secure, and non secure image in target.
 
 Run them in the following order to flash the board:
 
    .. code-block:: bash
 
       $ ./build/tfm/regression.sh
-      $ ./build/tfm/TFM_UPDATE.sh
-
-Reset the board.
+      $ west flash --hex-file build/tfm_merged.hex
 
  .. note::
-      Note that ``arm-none-eabi-gcc`` should be available in the PATH variable and that ``STM32_Programmer_CLI`` is required to run ``regression.sh`` and ``TFM_UPDATE.sh`` (see https://www.st.com/en/development-tools/stm32cubeprog.html). If you are still having trouble running these scripts, check the Programming and Debugging section of the :ref:`nucleo_l552ze_q_board` documentation.
+      Note that ``arm-none-eabi-gcc`` should be available in the PATH variable and that ``STM32_Programmer_CLI`` is required to run ``regression.sh`` (see https://www.st.com/en/development-tools/stm32cubeprog.html). If you are still having trouble running these scripts, check the Programming and Debugging section of the :ref:`nucleo_l552ze_q_board` or :ref:`stm32l562e_dk_board` documentation.
 
 On LPCxpresso55S69:
 ===================
diff --git a/samples/tfm_integration/tfm_ipc/boards/stm32l562e_dk_ns.overlay b/samples/tfm_integration/tfm_ipc/boards/stm32l562e_dk_ns.overlay
new file mode 100644
index 0000000000000000000000000000000000000000..b36ca6bfeb924e13741bcf8b48bdb415d8982504
--- /dev/null
+++ b/samples/tfm_integration/tfm_ipc/boards/stm32l562e_dk_ns.overlay
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Yestin Sun
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+ /* This partition table should be used along with TFM configuration:
+  * - TFM_PSA_API=ON (IPC)
+  * - ISOLATION_LEVEL 2
+  * - TEST_S=ON (REGRESSION)
+  * - TEST_NS=OFF (By default)
+  *
+  * In this configuration, TFM binary includes tests. As a consequence,
+  * its size is bloated and it is not possible to set secondary partitions
+  * for secured or non secured images.
+  */
+
+/ {
+	chosen {
+		zephyr,code-partition = &slot1_partition;
+	};
+};
+
+&flash0 {
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		boot_partition: partition@0 {
+			label = "mcuboot";
+			reg = <0x00000000 0x00013000>;
+			read-only;
+		};
+		/* Secure image primary slot */
+		slot0_partition: partition@00013000 {
+			label = "image-0";
+			reg = <0x00013000 0x00038000>;
+		};
+		/* Non-secure image primary slot */
+		slot1_partition: partition@0004B000 {
+			label = "image-1";
+			reg = <0x0004B000 0x0002A000>;
+		};
+		/*
+		 * The flash starting at 0x7F000 and ending at
+		 * 0x80000 is reserved for the application.
+		 */
+		storage_partition: partition@7F000 {
+			label = "storage";
+			reg = <0x0007F000 0x00001000>;
+		};
+	};
+};
diff --git a/samples/tfm_integration/tfm_ipc/sample.yaml b/samples/tfm_integration/tfm_ipc/sample.yaml
index 96c8f46f0dca3fdc8f17f359d0e92620e1c1feca..7814f173fb904a6e98787b2941819fc7e85b22a2 100644
--- a/samples/tfm_integration/tfm_ipc/sample.yaml
+++ b/samples/tfm_integration/tfm_ipc/sample.yaml
@@ -7,7 +7,7 @@ tests:
         tags: introduction tfm
         platform_allow: mps2_an521_nonsecure lpcxpresso55s69_ns
           nrf5340dk_nrf5340_cpuappns nrf9160dk_nrf9160ns nucleo_l552ze_q_ns
-          v2m_musca_s1_nonsecure
+          stm32l562e_dk_ns v2m_musca_s1_nonsecure
         harness: console
         harness_config:
           type: multi_line
diff --git a/scripts/kconfig/hardened.csv b/scripts/kconfig/hardened.csv
index 3c2b250ec3a9b3366ff487b8486259873be0352e..f62cae137a6955aaa7a5cd4cd0e0c601d79dde2c 100644
--- a/scripts/kconfig/hardened.csv
+++ b/scripts/kconfig/hardened.csv
@@ -20,7 +20,7 @@ ASSERT,n
 OBJECT_TRACING,n
 OVERRIDE_FRAME_POINTER_DEFAULT,y
 DEBUG_INFO,n
-OPENOCD_SUPPORT,n
+DEBUG_THREAD_INFO,n
 TRACING_CPU_STATS,n
 TRACING_CTF,n
 USE_SEGGER_RTT,n
@@ -76,7 +76,7 @@ NET_SOCKETS_ENABLE_DTLS,n,experimental
 NET_SOCKETS_NET_MGMT,n,experimental
 NET_SOCKETS_OFFLOAD,n,experimental
 NET_SOCKETS_SOCKOPT_TLS,n,experimental
-OPENOCD_SUPPORT,n,experimental
+DEBUG_THREAD_INFO,n,experimental
 PERFORMANCE_METRICS,n,experimental
 SHELL_TELNET_SUPPORT_COMMAND,n,experimental
 SPI_SLAVE,n,experimental
diff --git a/scripts/pylib/twister/harness.py b/scripts/pylib/twister/harness.py
index 2aed7567a2a45d14e2c6a4c8c88d0dc5038cd536..60debe324f1704e0ffb6a9642c1a6ae11a9c6446 100644
--- a/scripts/pylib/twister/harness.py
+++ b/scripts/pylib/twister/harness.py
@@ -132,18 +132,7 @@ class Test(Harness):
             self.tests[name] = match.group(1)
             self.ztest = True
 
-        if self.RUN_PASSED in line:
-            if self.fault:
-                self.state = "failed"
-            else:
-                self.state = "passed"
-
-        if self.RUN_FAILED in line:
-            self.state = "failed"
-
-        if self.fail_on_fault:
-            if self.FAULT in line:
-                self.fault = True
+        self.process_test(line)
 
         if not self.ztest and self.state:
             if self.state == "passed":
@@ -151,12 +140,6 @@ class Test(Harness):
             else:
                 self.tests[self.id] = "FAIL"
 
-        if self.GCOV_START in line:
-            self.capture_coverage = True
-        elif self.GCOV_END in line:
-            self.capture_coverage = False
-
-        self.process_test(line)
 
 class Ztest(Test):
     pass
diff --git a/soc/arm/nuvoton_npcx/common/CMakeLists.txt b/soc/arm/nuvoton_npcx/common/CMakeLists.txt
index f75aec6b311768683f83e53c263da7d3b734808c..cc72182a2950c97a8bd5925fe2f9815740c4ca88 100644
--- a/soc/arm/nuvoton_npcx/common/CMakeLists.txt
+++ b/soc/arm/nuvoton_npcx/common/CMakeLists.txt
@@ -1,3 +1,7 @@
 # SPDX-License-Identifier: Apache-2.0
 
 zephyr_include_directories(.)
+
+zephyr_sources(
+  scfg.c
+)
diff --git a/drivers/pinmux/pinmux_npcx.c b/soc/arm/nuvoton_npcx/common/scfg.c
similarity index 77%
rename from drivers/pinmux/pinmux_npcx.c
rename to soc/arm/nuvoton_npcx/common/scfg.c
index c73e3cc190b1edbb30b32d65f652297b23471193..63440f6c6ac5600227d2371f5468544fc8f81536 100644
--- a/drivers/pinmux/pinmux_npcx.c
+++ b/soc/arm/nuvoton_npcx/common/scfg.c
@@ -4,9 +4,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-#define DT_DRV_COMPAT nuvoton_npcx_pinctrl
-
-#include <drivers/pinmux.h>
+#include <device.h>
 #include <kernel.h>
 #include <soc.h>
 
@@ -14,7 +12,7 @@
 LOG_MODULE_REGISTER(pimux_npcx, LOG_LEVEL_ERR);
 
 /* Driver config */
-struct npcx_pinctrl_config {
+struct npcx_scfg_config {
 	/* scfg device base address */
 	uintptr_t base_scfg;
 	uintptr_t base_glue;
@@ -36,20 +34,20 @@ static const struct npcx_alt def_alts[] =
 
 static const struct npcx_lvol def_lvols[] = NPCX_DT_IO_LVOL_ITEMS_DEF_LIST;
 
-static const struct npcx_pinctrl_config npcx_pinctrl_cfg = {
-	.base_scfg = DT_INST_REG_ADDR_BY_NAME(0, scfg),
-	.base_glue = DT_INST_REG_ADDR_BY_NAME(0, glue),
+static const struct npcx_scfg_config npcx_scfg_cfg = {
+	.base_scfg = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), scfg),
+	.base_glue = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), glue),
 };
 
 /* Driver convenience defines */
-#define HAL_SFCG_INST() (struct scfg_reg *)(npcx_pinctrl_cfg.base_scfg)
+#define HAL_SFCG_INST() (struct scfg_reg *)(npcx_scfg_cfg.base_scfg)
 
-#define HAL_GLUE_INST() (struct glue_reg *)(npcx_pinctrl_cfg.base_glue)
+#define HAL_GLUE_INST() (struct glue_reg *)(npcx_scfg_cfg.base_glue)
 
 /* Pin-control local functions */
 static void npcx_pinctrl_alt_sel(const struct npcx_alt *alt, int alt_func)
 {
-	const uint32_t scfg_base = npcx_pinctrl_cfg.base_scfg;
+	const uint32_t scfg_base = npcx_scfg_cfg.base_scfg;
 	uint8_t alt_mask = BIT(alt->bit);
 
 	/*
@@ -79,7 +77,7 @@ void npcx_pinctrl_mux_configure(const struct npcx_alt *alts_list,
 
 void npcx_lvol_pads_configure(void)
 {
-	const uint32_t scfg_base = npcx_pinctrl_cfg.base_scfg;
+	const uint32_t scfg_base = npcx_scfg_cfg.base_scfg;
 
 	for (int i = 0; i < ARRAY_SIZE(def_lvols); i++) {
 		NPCX_LV_GPIO_CTL(scfg_base, def_lvols[i].ctrl)
@@ -101,7 +99,7 @@ void npcx_pinctrl_i2c_port_sel(int controller, int port)
 }
 
 /* Pin-control driver registration */
-static int npcx_pinctrl_init(const struct device *dev)
+static int npcx_scfg_init(const struct device *dev)
 {
 	struct scfg_reg *inst_scfg = HAL_SFCG_INST();
 
@@ -122,9 +120,4 @@ static int npcx_pinctrl_init(const struct device *dev)
 	return 0;
 }
 
-DEVICE_DT_DEFINE(DT_NODELABEL(scfg),
-		    &npcx_pinctrl_init,
-		    device_pm_control_nop,
-		    NULL, &npcx_pinctrl_cfg,
-		    PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
-		    NULL);
+SYS_INIT(npcx_scfg_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
diff --git a/soc/arm/nuvoton_npcx/common/soc_host.h b/soc/arm/nuvoton_npcx/common/soc_host.h
index 719bb46641ccdad62e1d5be643a47a78ac9866cd..b7f5e94f718eb79c271357f885a8ae50f6a8fdc1 100644
--- a/soc/arm/nuvoton_npcx/common/soc_host.h
+++ b/soc/arm/nuvoton_npcx/common/soc_host.h
@@ -68,6 +68,17 @@ int npcx_host_periph_read_request(enum lpc_peripheral_opcode op,
 int npcx_host_periph_write_request(enum lpc_peripheral_opcode op,
 							const uint32_t *data);
 
+/**
+ * @brief Enable host access wake-up interrupt. Usually, it is used to wake up
+ * ec during system is in Modern standby power mode.
+ */
+void npcx_host_enable_access_interrupt(void);
+
+/**
+ * @brief Disable host access wake-up interrupt.
+ */
+void npcx_host_disable_access_interrupt(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series
index 8ff1f3e76b487fbb3ed52da23f99475b65ab5a96..928280fe81ddb48f070b0d24f69d7e0d20a99069 100644
--- a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series
+++ b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series
@@ -22,12 +22,6 @@ config CLOCK_CONTROL_NPCX
 	help
 	  Enable support for NPCX clock controller driver.
 
-config PINMUX_NPCX
-	default y
-	depends on PINMUX
-	help
-	  Enable support for NPCX pinmux controller driver.
-
 config UART_NPCX
 	default y
 	depends on SERIAL
diff --git a/soc/arm/nuvoton_npcx/npcx7/power.c b/soc/arm/nuvoton_npcx/npcx7/power.c
index 328b6768aeb566e754e67cdc102ea403e79a5ac6..19637edc6fa15f224cfd4c6859c6d73d5f9edba5 100644
--- a/soc/arm/nuvoton_npcx/npcx7/power.c
+++ b/soc/arm/nuvoton_npcx/npcx7/power.c
@@ -46,9 +46,12 @@
  */
 
 #include <zephyr.h>
+#include <drivers/espi.h>
 #include <power/power.h>
 #include <soc.h>
 
+#include "soc_host.h"
+
 #include <logging/log.h>
 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
 
@@ -94,6 +97,9 @@ static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode)
 	npcx_clock_control_turn_on_system_sleep(slp_mode == NPCX_DEEP_SLEEP,
 					wk_mode == NPCX_INSTANT_WAKE_UP);
 
+	/* Turn on host access wake-up interrupt. */
+	npcx_host_enable_access_interrupt();
+
 	/*
 	 * Capture the reading of low-freq timer for compensation before ec
 	 * enters system sleep mode.
@@ -109,6 +115,9 @@ static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode)
 	 */
 	npcx_clock_compensate_system_timer();
 
+	/* Turn off host access wake-up interrupt. */
+	npcx_host_disable_access_interrupt();
+
 	/* Turn off system sleep mode. */
 	npcx_clock_control_turn_off_system_sleep();
 }
diff --git a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.efr32fg13p b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.efr32fg13p
new file mode 100644
index 0000000000000000000000000000000000000000..ec08102e57367cdbb4b3f97a2b7ea59e8b8840cb
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.efr32fg13p
@@ -0,0 +1,24 @@
+# Silicon Labs EFR32FG13P platform configuration options
+
+# Copyright (c) 2018 Christian Taedcke
+# SPDX-License-Identifier: Apache-2.0
+
+config GPIO_GECKO
+	default y
+	depends on GPIO
+
+config UART_GECKO
+	default y
+	depends on SERIAL
+
+config I2C_GECKO
+	default y
+	depends on I2C
+
+config SOC_FLASH_GECKO
+	default y
+	depends on FLASH
+
+config SPI_GECKO
+	default y
+	depends on SPI
diff --git a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.series b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.series
new file mode 100644
index 0000000000000000000000000000000000000000..c2850fc9822d5e7b51ce5a8a402335a2b2a4b383
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.series
@@ -0,0 +1,20 @@
+# EFR32FG13P series configuration options
+
+# Copyright (c) 2018 Christian Taedcke
+# SPDX-License-Identifier: Apache-2.0
+
+if SOC_SERIES_EFR32FG13P
+
+config SOC_SERIES
+	default "efr32fg13p"
+
+config SOC_PART_NUMBER
+	default "EFR32FG13P233F512GM48" if SOC_PART_NUMBER_EFR32FG13P233F512GM48
+
+config NUM_IRQS
+	# must be >= the highest interrupt number used
+	default 45
+
+source "soc/arm/silabs_exx32/efr32fg13p/Kconfig.defconfig.efr32fg13p"
+
+endif # SOC_SERIES_EFR32FG13P
diff --git a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series
new file mode 100644
index 0000000000000000000000000000000000000000..1913377b3e70e8f15c60664f1d23f14073e3b929
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series
@@ -0,0 +1,22 @@
+# EFR32FG13P MCU line
+
+# Copyright (c) 2018 Christian Taedcke
+# SPDX-License-Identifier: Apache-2.0
+
+config SOC_SERIES_EFR32FG13P
+	bool "EFR32FG13P Series MCU"
+	select ARM
+	select HAS_SILABS_GECKO
+	select HAS_SWO
+	select CPU_CORTEX_M4
+	select CPU_CORTEX_M_HAS_DWT
+	select CPU_HAS_FPU
+	select CPU_HAS_ARM_MPU
+	select SOC_FAMILY_EXX32
+	select SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION
+	select SOC_GECKO_HAS_HFRCO_FREQRANGE
+	select SOC_GECKO_CMU
+	select SOC_GECKO_GPIO
+	select SOC_GECKO_HAS_ERRATA_RTCC_E201
+	help
+	  Enable support for EFR32 FlexGecko MCU series
diff --git a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.soc b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.soc
new file mode 100644
index 0000000000000000000000000000000000000000..e79517fb536752103fdd7058dc2b0831246f26bc
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.soc
@@ -0,0 +1,8 @@
+# EFR32FG13P (Flex Gecko) MCU line
+
+# Copyright (c) 2018 Christian Taedcke
+# SPDX-License-Identifier: Apache-2.0
+
+config SOC_PART_NUMBER_EFR32FG13P233F512GM48
+	bool
+	depends on SOC_SERIES_EFR32FG13P
diff --git a/soc/arm/silabs_exx32/efr32fg13p/linker.ld b/soc/arm/silabs_exx32/efr32fg13p/linker.ld
new file mode 100644
index 0000000000000000000000000000000000000000..22ea2d25e5c243feeb93176984468a6cf159ca82
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/linker.ld
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018 Christian Taedcke
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief Linker command/script file
+ *
+ * This is the linker script for both standard images.
+ */
+
+#include <autoconf.h>
+
+#include <arch/arm/aarch32/cortex_m/scripts/linker.ld>
diff --git a/soc/arm/silabs_exx32/efr32fg13p/soc.h b/soc/arm/silabs_exx32/efr32fg13p/soc.h
new file mode 100644
index 0000000000000000000000000000000000000000..770ef4ca77e9b8c63f81581272cef507d23e3047
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/soc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Christian Taedcke
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief Board configuration macros for the efr32fg13p soc
+ *
+ */
+
+#ifndef _SOC__H_
+#define _SOC__H_
+
+#include <sys/util.h>
+
+#ifndef _ASMLANGUAGE
+
+#include <em_bus.h>
+#include <em_common.h>
+
+/* Add include for DTS generated information */
+#include <devicetree.h>
+
+#include "soc_pinmap.h"
+#include "../common/soc_gpio.h"
+
+#endif /* !_ASMLANGUAGE */
+
+#endif /* _SOC__H_ */
diff --git a/soc/arm/silabs_exx32/efr32fg13p/soc_pinmap.h b/soc/arm/silabs_exx32/efr32fg13p/soc_pinmap.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d802e43709252d2fa4dc6205f6dabeb687c95c6
--- /dev/null
+++ b/soc/arm/silabs_exx32/efr32fg13p/soc_pinmap.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Christian Taedcke
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/** @file
+ * @brief Silabs EFR32FG13P MCU pin definitions.
+ *
+ * This file contains pin configuration data required by different MCU
+ * modules to correctly configure GPIO controller.
+ */
+
+#ifndef _SILABS_EFR32FG13P_SOC_PINMAP_H_
+#define _SILABS_EFR32FG13P_SOC_PINMAP_H_
+
+#include <soc.h>
+#include <em_gpio.h>
+
+#define GPIO_NODE DT_INST(0, silabs_gecko_gpio)
+#if DT_NODE_HAS_PROP(GPIO_NODE, location_swo)
+#define SWO_LOCATION DT_PROP(GPIO_NODE, location_swo)
+#endif
+
+/* Serial Wire Output (SWO) */
+#if (SWO_LOCATION == 0)
+#define PIN_SWO {gpioPortF, 2, gpioModePushPull, 1}
+#elif (SWO_LOCATION == 1)
+#define PIN_SWO {gpioPortB, 13, gpioModePushPull, 1}
+#elif (SWO_LOCATION == 2)
+#define PIN_SWO {gpioPortD, 15, gpioModePushPull, 1}
+#elif (SWO_LOCATION == 3)
+#define PIN_SWO {gpioPortC, 11, gpioModePushPull, 1}
+#elif (SWO_LOCATION >= 4)
+#error ("Invalid SWO pin location")
+#endif
+
+#endif /* _SILABS_EFR32FG13P_SOC_PINMAP_H_ */
diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig
index 7073147ae15e315fad6568dd10b606258158ee35..c9d717f25930f064280b1e1eb438e2b6e3e4f756 100644
--- a/subsys/bluetooth/controller/Kconfig
+++ b/subsys/bluetooth/controller/Kconfig
@@ -372,6 +372,10 @@ config BT_CTLR_CONN_RSSI
 	help
 	  Enable connection RSSI measurement.
 
+config BT_CTLR_CHECK_SAME_PEER_CONN
+	bool
+	default BT_MAX_CONN > 1 && !BT_CTLR_ALLOW_SAME_PEER_CONN
+
 endif # BT_CONN
 
 config BT_CTLR_FILTER
diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split
index 8cef936fb3e139eb10c576f0a01cec7c766963d4..547652e8ec02a5400614aecc6261e3dcc5b18ff9 100644
--- a/subsys/bluetooth/controller/Kconfig.ll_sw_split
+++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split
@@ -475,6 +475,18 @@ config BT_CTLR_CONN_RSSI_EVENT
 	help
 	  Generate events for connection RSSI measurement.
 
+config BT_CTLR_ALLOW_SAME_PEER_CONN
+	bool "Allow connection requests from same peer"
+	depends on BT_MAX_CONN > 1
+	help
+	  Allow connection requests from the same peer. While the
+	  Bluetooth specification does not allow multiple connections
+	  with the same peer, allowing such connections is useful
+	  while debugging multiple connections.
+
+	  WARNING: This option enables behavior that violates the Bluetooth
+	  specification.
+
 endif # BT_CONN
 
 config BT_CTLR_ADV_INDICATION
diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c
index a9e831d951dac3f36a40353c9d68edce3774c264..c695bc08bd9789c704ac92a824932939ce025802 100644
--- a/subsys/bluetooth/controller/hci/hci.c
+++ b/subsys/bluetooth/controller/hci/hci.c
@@ -682,12 +682,28 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt)
 			    BIT(6) | BIT(7);
 	/* LE Remove Adv Set, LE Clear Adv Sets */
 	rp->commands[37] |= BIT(0) | BIT(1);
+#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
+	/* LE Set PA Params, LE Set PA Data, LE Set PA Enable */
+	rp->commands[37] |= BIT(2) | BIT(3) | BIT(4);
+#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
 #endif /* CONFIG_BT_CTLR_ADV_EXT */
 #endif /* CONFIG_BT_BROADCASTER */
 
 #if defined(CONFIG_BT_OBSERVER)
 	/* LE Set Scan Params, LE Set Scan Enable */
 	rp->commands[26] |= BIT(2) | BIT(3);
+
+#if defined(CONFIG_BT_CTLR_ADV_EXT)
+	/* LE Set Extended Scan Params, LE Set Extended Scan Enable */
+	rp->commands[37] |= BIT(5) | BIT(6);
+#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
+	/* LE PA Create Sync, LE PA Create Sync Cancel, LE PA Terminate Sync */
+	rp->commands[38] |= BIT(0) | BIT(1) | BIT(2);
+	/* LE Set PA Receive Enable */
+	rp->commands[40] |= BIT(5);
+#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
+#endif /* CONFIG_BT_CTLR_ADV_EXT */
+
 #endif /* CONFIG_BT_OBSERVER */
 
 #if defined(CONFIG_BT_CONN)
@@ -697,6 +713,11 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt)
 	/* Set Host Channel Classification */
 	rp->commands[27] |= BIT(3);
 
+#if defined(CONFIG_BT_CTLR_ADV_EXT)
+	/* LE Extended Create Connection */
+	rp->commands[37] |= BIT(7);
+#endif /* CONFIG_BT_CTLR_ADV_EXT */
+
 #if defined(CONFIG_BT_CTLR_LE_ENC)
 	/* LE Start Encryption */
 	rp->commands[28] |= BIT(0);
diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.c b/subsys/bluetooth/controller/ll_sw/lll_chan.c
index ace2cd390bc27214a5192d4f73ac4e88581fed45..ffca8d0585117355ae89fe957c51ee301b68e784 100644
--- a/subsys/bluetooth/controller/ll_sw/lll_chan.c
+++ b/subsys/bluetooth/controller/ll_sw/lll_chan.c
@@ -44,6 +44,14 @@ uint8_t lll_chan_sel_1(uint8_t *chan_use, uint8_t hop, uint16_t latency, uint8_t
 #endif /* CONFIG_BT_CONN */
 
 #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
+uint16_t lll_chan_id(uint8_t *access_addr)
+{
+	uint16_t aa_ls = ((uint16_t)access_addr[1] << 8) | access_addr[0];
+	uint16_t aa_ms = ((uint16_t)access_addr[3] << 8) | access_addr[2];
+
+	return aa_ms ^ aa_ls;
+}
+
 uint8_t lll_chan_sel_2(uint16_t counter, uint16_t chan_id, uint8_t *chan_map,
 		    uint8_t chan_count)
 {
diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.h b/subsys/bluetooth/controller/ll_sw/lll_chan.h
index 006271736735dba5365b6bc9cc661d655eb01cc1..d3846508e73f8b31a460e2d3deb7928e07ed303f 100644
--- a/subsys/bluetooth/controller/ll_sw/lll_chan.h
+++ b/subsys/bluetooth/controller/ll_sw/lll_chan.h
@@ -6,5 +6,6 @@
 
 uint8_t lll_chan_sel_1(uint8_t *chan_use, uint8_t hop, uint16_t latency, uint8_t *chan_map,
 		    uint8_t chan_count);
+uint16_t lll_chan_id(uint8_t *access_addr);
 uint8_t lll_chan_sel_2(uint16_t counter, uint16_t chan_id, uint8_t *chan_map,
 		    uint8_t chan_count);
diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c
index 885d88e437a3393c8a06181039a6be7063cfb501..ea9358cfa9c3a3f648a51a62918e672a4b66383e 100644
--- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c
+++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c
@@ -1333,8 +1333,7 @@ static inline int isr_rx_pdu(struct lll_adv *lll,
 		   lll_adv_connect_ind_check(lll, pdu_rx, tx_addr, addr,
 					     rx_addr, tgt_addr,
 					     devmatch_ok, &rl_idx) &&
-		   lll->conn &&
-		   !lll->conn->initiated) {
+		   lll->conn) {
 		struct node_rx_ftr *ftr;
 		struct node_rx_pdu *rx;
 
diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c
index 99f0e44a1b251821d0c048bee4066025d9e577f0..db7dd409b4f631eccc7d6c039e610c08069be508 100644
--- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c
+++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c
@@ -577,8 +577,7 @@ static inline int isr_rx_pdu(struct lll_adv_aux *lll_aux,
 		   lll_adv_connect_ind_check(lll, pdu_rx, tx_addr, addr,
 					     rx_addr, tgt_addr,
 					     devmatch_ok, &rl_idx) &&
-		   lll->conn &&
-		   !lll->conn->initiated) {
+		   lll->conn) {
 		struct node_rx_ftr *ftr;
 		struct node_rx_pdu *rx;
 		struct pdu_adv *pdu_tx;
diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c
index b73dc29f585b590e401bb092bbfa29866faddba8..ff5353afe9455506c9d918f4cca922c7cd2c669d 100644
--- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c
+++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c
@@ -777,7 +777,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx,
 	if (0) {
 #if defined(CONFIG_BT_CENTRAL)
 	/* Initiator */
-	} else if (lll->conn && !lll->conn->initiated &&
+	} else if (lll->conn &&
 		   isr_scan_init_check(lll, pdu_adv_rx, rl_idx)) {
 		struct lll_conn *lll_conn;
 		struct node_rx_ftr *ftr;
diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c
index 4a76d93d7262a88e992d1031a0913523704f573c..d41d6b038dd41967a53f45114f7b59c57699e535 100644
--- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c
+++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c
@@ -898,8 +898,7 @@ static inline int isr_rx_pdu(struct lll_adv *lll,
 		   (pdu_rx->len == sizeof(struct pdu_adv_connect_ind)) &&
 		   isr_rx_ci_check(lll, pdu_adv, pdu_rx, devmatch_ok,
 				   &rl_idx) &&
-		   lll->conn &&
-		   !lll->conn->initiated) {
+		   lll->conn) {
 		struct node_rx_ftr *ftr;
 		struct node_rx_pdu *rx;
 
diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c
index 30e8cbb5f2b2c1670cb5a2f833a472a6334dddac..fa6e7f96bdf855baa10fa9c25a9eb8d540fecc2e 100644
--- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c
+++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c
@@ -674,7 +674,7 @@ static inline uint32_t isr_rx_pdu(struct lll_scan *lll, uint8_t devmatch_ok,
 	if (0) {
 #if defined(CONFIG_BT_CENTRAL)
 	/* Initiator */
-	} else if (lll->conn && !lll->conn->initiated &&
+	} else if (lll->conn &&
 		   isr_scan_init_check(lll, pdu_adv_rx, rl_idx)) {
 		struct lll_conn *lll_conn;
 		struct node_rx_ftr *ftr;
diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c
index 5263942d3952235821e556e425ce855420b0451a..fe07ba3e62b1325b4d7a1a97335098f78724d74e 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_adv.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c
@@ -365,8 +365,8 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type,
 	adv->own_addr_type = own_addr_type;
 	if (adv->own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
 	    adv->own_addr_type == BT_ADDR_LE_RANDOM_ID) {
-		adv->id_addr_type = direct_addr_type;
-		memcpy(&adv->id_addr, direct_addr, BDADDR_SIZE);
+		adv->peer_addr_type = direct_addr_type;
+		memcpy(&adv->peer_addr, direct_addr, BDADDR_SIZE);
 	}
 #endif /* CONFIG_BT_CTLR_PRIVACY */
 
@@ -718,8 +718,8 @@ uint8_t ll_adv_enable(uint8_t enable)
 	if (adv->own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
 	    adv->own_addr_type == BT_ADDR_LE_RANDOM_ID) {
 		/* Look up the resolving list */
-		lll->rl_idx = ull_filter_rl_find(adv->id_addr_type,
-						 adv->id_addr, NULL);
+		lll->rl_idx = ull_filter_rl_find(adv->peer_addr_type,
+						 adv->peer_addr, NULL);
 
 		if (lll->rl_idx != FILTER_IDX_NONE) {
 			/* Generate RPAs if required */
@@ -893,6 +893,13 @@ uint8_t ll_adv_enable(uint8_t enable)
 		conn->supervision_expire = 0;
 		conn->procedure_expire = 0;
 
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+		conn->own_addr_type = BT_ADDR_LE_NONE->type;
+		memcpy(conn->own_addr, BT_ADDR_LE_NONE->a.val, sizeof(conn->own_addr));
+		conn->peer_addr_type = BT_ADDR_LE_NONE->type;
+		memcpy(conn->peer_addr, BT_ADDR_LE_NONE->a.val, sizeof(conn->peer_addr));
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 		conn->common.fex_valid = 0;
 		conn->slave.latency_cancel = 0;
 
@@ -2089,20 +2096,34 @@ static inline uint8_t *adv_pdu_adva_get(struct pdu_adv *pdu)
 static const uint8_t *adva_update(struct ll_adv_set *adv, struct pdu_adv *pdu)
 {
 #if defined(CONFIG_BT_CTLR_PRIVACY)
-	const uint8_t *tx_addr = ull_filter_adva_get(adv);
+	const uint8_t *rpa = ull_filter_adva_get(adv);
 #else
-	const uint8_t *tx_addr = NULL;
+	const uint8_t *rpa = NULL;
 #endif
+	const uint8_t *own_addr;
+	const uint8_t *tx_addr;
 	uint8_t *adv_addr;
 
-	if (tx_addr) {
-		pdu->tx_addr = 1;
+	if (!rpa || IS_ENABLED(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)) {
+		if (0) {
 #if defined(CONFIG_BT_CTLR_ADV_EXT)
-	} else if (ll_adv_cmds_is_ext() && pdu->tx_addr) {
-		tx_addr = ll_adv_aux_random_addr_get(adv, NULL);
+		} else if (ll_adv_cmds_is_ext() && pdu->tx_addr) {
+			own_addr = ll_adv_aux_random_addr_get(adv, NULL);
 #endif
+		} else {
+			own_addr = ll_addr_get(pdu->tx_addr, NULL);
+		}
+	}
+
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+	memcpy(adv->own_addr, own_addr, BDADDR_SIZE);
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
+	if (rpa) {
+		pdu->tx_addr = 1;
+		tx_addr = rpa;
 	} else {
-		tx_addr = ll_addr_get(pdu->tx_addr, NULL);
+		tx_addr = own_addr;
 	}
 
 	adv_addr = adv_pdu_adva_get(pdu);
diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c
index 41cc62077117cd212e72c6bcedf3c013021a28b4..dd86ff8923ff0c7df0632e7f432fb1d91d9d968e 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c
@@ -28,6 +28,7 @@
 #include "lll/lll_adv_pdu.h"
 #include "lll_adv_sync.h"
 #include "lll/lll_df_types.h"
+#include "lll_chan.h"
 
 #include "ull_adv_types.h"
 
@@ -120,16 +121,16 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
 		err = util_aa_le32(lll_sync->access_addr);
 		LL_ASSERT(!err);
 
+		lll_sync->data_chan_id = lll_chan_id(lll_sync->access_addr);
+		lll_sync->data_chan_count =
+			ull_chan_map_get(lll_sync->data_chan_map);
+
 		lll_csrand_get(lll_sync->crc_init, sizeof(lll_sync->crc_init));
 
 		lll_sync->latency_prepare = 0;
 		lll_sync->latency_event = 0;
 		lll_sync->event_counter = 0;
 
-		lll_sync->data_chan_count =
-			ull_chan_map_get(lll_sync->data_chan_map);
-		lll_sync->data_chan_id = 0;
-
 		sync->is_enabled = 0U;
 		sync->is_started = 0U;
 
diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h
index 325b4b9e4e84f4ac6c0b01b4cbf046ece53a40c1..fbe9f40c77634c61ab2cb6674d173de2e7e6793a 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h
+++ b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h
@@ -37,10 +37,14 @@ struct ll_adv_set {
 
 #if defined(CONFIG_BT_CTLR_PRIVACY)
 	uint8_t  own_addr_type:2;
-	uint8_t  id_addr_type:1;
-	uint8_t  id_addr[BDADDR_SIZE];
+	uint8_t  peer_addr_type:1;
+	uint8_t  peer_addr[BDADDR_SIZE];
 #endif /* CONFIG_BT_CTLR_PRIVACY */
 
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+	uint8_t  own_addr[BDADDR_SIZE];
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
 	struct lll_df_adv_cfg *df_cfg;
 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c
index 28af2c53d48cdfecbf8562cb517f4abd361ee7c1..85a0b573ba53b35aa14c607701629d4f86c00c6a 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_conn.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c
@@ -91,6 +91,7 @@ static inline void event_ch_map_prep(struct ll_conn *conn,
 				     uint16_t event_counter);
 
 #if defined(CONFIG_BT_CTLR_LE_ENC)
+static inline void ctrl_tx_check_and_resume(struct ll_conn *conn);
 static bool is_enc_req_pause_tx(struct ll_conn *conn);
 static inline void event_enc_prep(struct ll_conn *conn);
 #if defined(CONFIG_BT_PERIPHERAL)
@@ -770,6 +771,28 @@ uint8_t ull_conn_default_phy_rx_get(void)
 }
 #endif /* CONFIG_BT_CTLR_PHY */
 
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+bool ull_conn_peer_connected(uint8_t own_addr_type, uint8_t *own_addr,
+			     uint8_t peer_addr_type, uint8_t *peer_addr)
+{
+	uint16_t handle;
+
+	for (handle = 0U; handle < CONFIG_BT_MAX_CONN; handle++) {
+		struct ll_conn *conn = ll_connected_get(handle);
+
+		if (conn &&
+		    conn->peer_addr_type == peer_addr_type &&
+		    !memcmp(conn->peer_addr, peer_addr, BDADDR_SIZE) &&
+		    conn->own_addr_type == own_addr_type &&
+		    !memcmp(conn->own_addr, own_addr, BDADDR_SIZE)) {
+			return true;
+		}
+	}
+
+	return false;
+}
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 void ull_conn_setup(memq_link_t *link, struct node_rx_hdr *rx)
 {
 	struct node_rx_ftr *ftr;
@@ -1846,18 +1869,11 @@ static void tx_demux(void *param)
 
 static struct node_tx *tx_ull_dequeue(struct ll_conn *conn, struct node_tx *tx)
 {
+#if defined(CONFIG_BT_CTLR_LE_ENC)
 	if (!conn->tx_ctrl && (conn->tx_head != conn->tx_data)) {
-		struct pdu_data *pdu_data_tx;
-
-		pdu_data_tx = (void *)conn->tx_head->pdu;
-		if ((pdu_data_tx->ll_id != PDU_DATA_LLID_CTRL) ||
-		    ((pdu_data_tx->llctrl.opcode !=
-		      PDU_DATA_LLCTRL_TYPE_ENC_REQ) &&
-		     (pdu_data_tx->llctrl.opcode !=
-		      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
-			conn->tx_ctrl = conn->tx_ctrl_last = conn->tx_head;
-		}
+		ctrl_tx_check_and_resume(conn);
 	}
+#endif /* CONFIG_BT_CTLR_LE_ENC */
 
 	if (conn->tx_head == conn->tx_ctrl) {
 		conn->tx_head = conn->tx_head->next;
@@ -1968,8 +1984,24 @@ static int empty_data_start_release(struct ll_conn *conn, struct node_tx *tx)
 }
 #endif /* CONFIG_BT_CTLR_LLID_DATA_START_EMPTY */
 
-static void ctrl_tx_last_enqueue(struct ll_conn *conn,
-				      struct node_tx *tx)
+#if defined(CONFIG_BT_CTLR_LE_ENC)
+static inline void  ctrl_tx_check_and_resume(struct ll_conn *conn)
+{
+	struct pdu_data *pdu_data_tx;
+
+	pdu_data_tx = (void *)conn->tx_head->pdu;
+	if ((pdu_data_tx->ll_id != PDU_DATA_LLID_CTRL) ||
+	    ((pdu_data_tx->llctrl.opcode !=
+	      PDU_DATA_LLCTRL_TYPE_ENC_REQ) &&
+	     (pdu_data_tx->llctrl.opcode !=
+	      PDU_DATA_LLCTRL_TYPE_PAUSE_ENC_REQ))) {
+		conn->tx_ctrl = conn->tx_ctrl_last = conn->tx_head;
+	}
+}
+#endif /* CONFIG_BT_CTLR_LE_ENC */
+
+static inline void ctrl_tx_last_enqueue(struct ll_conn *conn,
+					struct node_tx *tx)
 {
 	tx->next = conn->tx_ctrl_last->next;
 	conn->tx_ctrl_last->next = tx;
@@ -2000,6 +2032,10 @@ static inline void ctrl_tx_pause_enqueue(struct ll_conn *conn,
 		 */
 		if (conn->tx_head == conn->tx_data) {
 			conn->tx_data = conn->tx_data->next;
+#if defined(CONFIG_BT_CTLR_LE_ENC)
+		} else if (!conn->tx_ctrl) {
+			ctrl_tx_check_and_resume(conn);
+#endif /* CONFIG_BT_CTLR_LE_ENC */
 		}
 
 		/* if no ctrl packet already queued, new ctrl added will be
diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h
index d4a690198654cc35a615cb634ef74e6390fe7fed..83199c2bfdea0af931cef2d043155a1153eb5711 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h
+++ b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h
@@ -17,6 +17,8 @@ uint16_t ull_conn_default_tx_octets_get(void);
 uint16_t ull_conn_default_tx_time_get(void);
 uint8_t ull_conn_default_phy_tx_get(void);
 uint8_t ull_conn_default_phy_rx_get(void);
+bool ull_conn_peer_connected(uint8_t own_addr_type, uint8_t *own_addr,
+			     uint8_t peer_addr_type, uint8_t *peer_addr);
 void ull_conn_setup(memq_link_t *link, struct node_rx_hdr *rx);
 int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx);
 int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint16_t lazy);
diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h
index 9231a3650cdff06d6f7b960f2b6d4be033c26621..a1ac1f088d7d9e2793b5be9747f61f2f559b56b7 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h
+++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h
@@ -56,6 +56,13 @@ struct ll_conn {
 #endif /* CONFIG_BT_CTLR_PHY */
 #endif /* CONFIG_BT_CTLR_DATA_LENGTH */
 
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+	uint8_t own_addr_type:1;
+	uint8_t peer_addr_type:2;
+	uint8_t own_addr[BDADDR_SIZE];
+	uint8_t peer_addr[BDADDR_SIZE];
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 	union {
 		struct {
 			uint8_t fex_valid:1;
diff --git a/subsys/bluetooth/controller/ll_sw/ull_filter.c b/subsys/bluetooth/controller/ll_sw/ull_filter.c
index 127db1b4816962a10fafcb4c81ad83ac8862bc3a..905abef4463e097275bcbccb13ee648a21c57b0a 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_filter.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_filter.c
@@ -31,11 +31,13 @@
 
 #include "ull_adv_types.h"
 #include "ull_scan_types.h"
+#include "ull_conn_types.h"
 #include "ull_filter.h"
 
 #include "ull_internal.h"
 #include "ull_adv_internal.h"
 #include "ull_scan_internal.h"
+#include "ull_conn_internal.h"
 
 #include "ll.h"
 
@@ -139,6 +141,11 @@ static void filter_insert(struct lll_filter *filter, int index, uint8_t addr_typ
 			   uint8_t *bdaddr);
 static void filter_clear(struct lll_filter *filter);
 
+#if defined(CONFIG_BT_CTLR_PRIVACY) && \
+	defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+static void conn_rpa_update(uint8_t rl_idx);
+#endif /* CONFIG_BT_CTLR_PRIVACY && CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 #if defined(CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY)
 static void prpa_cache_clear(void);
 static uint8_t prpa_cache_find(bt_addr_t *prpa_cache_addr);
@@ -374,6 +381,9 @@ void ll_rl_crpa_set(uint8_t id_addr_type, uint8_t *id_addr, uint8_t rl_idx, uint
 		if (rl_idx < ARRAY_SIZE(rl) && rl[rl_idx].taken) {
 			memcpy(rl[rl_idx].curr_rpa.val, crpa,
 			       sizeof(bt_addr_t));
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+			conn_rpa_update(rl_idx);
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN) */
 		}
 	}
 }
@@ -1083,6 +1093,27 @@ static void filter_clear(struct lll_filter *filter)
 	filter->addr_type_bitmask = 0;
 }
 
+#if defined(CONFIG_BT_CTLR_PRIVACY) && \
+	defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+static void conn_rpa_update(uint8_t rl_idx)
+{
+	uint16_t handle;
+
+	for (handle = 0U; handle < CONFIG_BT_MAX_CONN; handle++) {
+		struct ll_conn *conn = ll_connected_get(handle);
+
+		/* The RPA of the connection matches the RPA that was just resolved */
+		if (conn &&
+		    conn->peer_addr_type < 2U &&
+		    !memcmp(conn->peer_addr, rl[rl_idx].curr_rpa.val, BDADDR_SIZE)) {
+			memcpy(conn->peer_addr, rl[rl_idx].id_addr.val, BDADDR_SIZE);
+			conn->peer_addr_type += 2U;
+			break;
+		}
+	}
+}
+#endif /* CONFIG_BT_CTLR_PRIVACY && CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 #if defined(CONFIG_BT_CTLR_SW_DEFERRED_PRIVACY)
 static void target_resolve(struct k_work *work)
 {
@@ -1171,6 +1202,9 @@ static void prpa_cache_resolve(struct k_work *work)
 			 */
 			memcpy(rl[j].curr_rpa.val, search_rpa->val,
 			       sizeof(bt_addr_t));
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+			conn_rpa_update(j);
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
 		}
 
 	} else {
diff --git a/subsys/bluetooth/controller/ll_sw/ull_master.c b/subsys/bluetooth/controller/ll_sw/ull_master.c
index e6f6c338b64e0722281839e78e37a823d30a7de5..541f8735a1863bfdd8e1294c9ab86168a3de88c0 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_master.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_master.c
@@ -28,6 +28,7 @@
 #include "lll/lll_adv_types.h"
 #include "lll_adv.h"
 #include "lll/lll_adv_pdu.h"
+#include "lll_chan.h"
 #include "lll_scan.h"
 #include "lll_conn.h"
 #include "lll_master.h"
@@ -735,13 +736,8 @@ void ull_master_setup(memq_link_t *link, struct node_rx_hdr *rx,
 		cs = (void *)rx_csa->pdu;
 
 		if (chan_sel) {
-			uint16_t aa_ls = ((uint16_t)lll->access_addr[1] << 8) |
-				      lll->access_addr[0];
-			uint16_t aa_ms = ((uint16_t)lll->access_addr[3] << 8) |
-				      lll->access_addr[2];
-
 			lll->data_chan_sel = 1;
-			lll->data_chan_id = aa_ms ^ aa_ls;
+			lll->data_chan_id = lll_chan_id(lll->access_addr);
 
 			cs->csa = 0x01;
 		} else {
diff --git a/subsys/bluetooth/controller/ll_sw/ull_slave.c b/subsys/bluetooth/controller/ll_sw/ull_slave.c
index f995c09a5f118bcd2aed5184500d3f361394d08a..75b9c965262d7c370d21fd6b58e7d574966d9004 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_slave.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_slave.c
@@ -28,6 +28,7 @@
 #include "lll/lll_adv_types.h"
 #include "lll_adv.h"
 #include "lll/lll_adv_pdu.h"
+#include "lll_chan.h"
 #include "lll_conn.h"
 #include "lll_slave.h"
 #include "lll_filter.h"
@@ -58,6 +59,7 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
 {
 	uint32_t conn_offset_us, conn_interval_us;
 	uint8_t ticker_id_adv, ticker_id_conn;
+	uint8_t peer_id_addr[BDADDR_SIZE];
 	uint8_t peer_addr[BDADDR_SIZE];
 	uint32_t ticks_slot_overhead;
 	uint32_t ticks_slot_offset;
@@ -78,6 +80,46 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
 
 	/* Populate the slave context */
 	pdu_adv = (void *)((struct node_rx_pdu *)rx)->pdu;
+
+	peer_addr_type = pdu_adv->tx_addr;
+	memcpy(peer_addr, pdu_adv->connect_ind.init_addr, BDADDR_SIZE);
+
+#if defined(CONFIG_BT_CTLR_PRIVACY)
+	uint8_t rl_idx = ftr->rl_idx;
+
+	if (rl_idx != FILTER_IDX_NONE) {
+		/* Get identity address */
+		ll_rl_id_addr_get(rl_idx, &peer_addr_type, peer_id_addr);
+		/* Mark it as identity address from RPA (0x02, 0x03) */
+		peer_addr_type += 2;
+	} else {
+#else /* CONFIG_BT_CTLR_PRIVACY */
+	if (1) {
+#endif /* CONFIG_BT_CTLR_PRIVACY */
+		memcpy(peer_id_addr, peer_addr, BDADDR_SIZE);
+	}
+
+#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
+	uint8_t own_addr_type = pdu_adv->rx_addr;
+	uint8_t *own_addr = adv->own_addr;
+
+	/* Do not connect twice to the same peer */
+	if (ull_conn_peer_connected(own_addr_type, own_addr,
+				    peer_addr_type, peer_id_addr)) {
+		rx->type = NODE_RX_TYPE_RELEASE;
+
+		ll_rx_put(link, rx);
+		ll_rx_sched();
+		return;
+	}
+
+	/* Remember peer and own identity */
+	conn->peer_addr_type = peer_addr_type;
+	memcpy(conn->peer_addr, peer_id_addr, sizeof(conn->peer_addr));
+	conn->own_addr_type = own_addr_type;
+	memcpy(conn->own_addr, own_addr, sizeof(conn->own_addr));
+#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
+
 	memcpy(&lll->crc_init[0], &pdu_adv->connect_ind.crc_init[0], 3);
 	memcpy(&lll->access_addr[0], &pdu_adv->connect_ind.access_addr[0], 4);
 	memcpy(&lll->data_chan_map[0], &pdu_adv->connect_ind.chan_map[0],
@@ -176,9 +218,6 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
 	       sizeof(conn->slave.force));
 #endif /* CONFIG_BT_CTLR_CONN_RANDOM_FORCE */
 
-	peer_addr_type = pdu_adv->tx_addr;
-	memcpy(peer_addr, pdu_adv->connect_ind.init_addr, BDADDR_SIZE);
-
 	if (0) {
 #if defined(CONFIG_BT_CTLR_ADV_EXT)
 	} else if (adv->lll.aux) {
@@ -193,8 +232,6 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
 	cc->role = 1U;
 
 #if defined(CONFIG_BT_CTLR_PRIVACY)
-	uint8_t rl_idx = ftr->rl_idx;
-
 	if (ull_filter_lll_lrpa_used(adv->lll.rl_idx)) {
 		memcpy(&cc->local_rpa[0], &pdu_adv->connect_ind.adv_addr[0],
 		       BDADDR_SIZE);
@@ -203,23 +240,15 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
 	}
 
 	if (rl_idx != FILTER_IDX_NONE) {
-		/* TODO: store rl_idx instead if safe */
-		/* Store identity address */
-		ll_rl_id_addr_get(rl_idx, &cc->peer_addr_type,
-				  &cc->peer_addr[0]);
-		/* Mark it as identity address from RPA (0x02, 0x03) */
-		cc->peer_addr_type += 2;
-
 		/* Store peer RPA */
-		memcpy(&cc->peer_rpa[0], &peer_addr[0], BDADDR_SIZE);
+		memcpy(cc->peer_rpa, peer_addr, BDADDR_SIZE);
 	} else {
-		memset(&cc->peer_rpa[0], 0x0, BDADDR_SIZE);
-#else
-	if (1) {
-#endif /* CONFIG_BT_CTLR_PRIVACY */
-		cc->peer_addr_type = peer_addr_type;
-		memcpy(cc->peer_addr, peer_addr, BDADDR_SIZE);
+		memset(cc->peer_rpa, 0x0, BDADDR_SIZE);
 	}
+#endif /* CONFIG_BT_CTLR_PRIVACY */
+
+	cc->peer_addr_type = peer_addr_type;
+	memcpy(cc->peer_addr, peer_id_addr, BDADDR_SIZE);
 
 	cc->interval = lll->interval;
 	cc->latency = lll->latency;
@@ -256,13 +285,8 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
 		cs = (void *)rx_csa->pdu;
 
 		if (chan_sel) {
-			uint16_t aa_ls = ((uint16_t)lll->access_addr[1] << 8) |
-				      lll->access_addr[0];
-			uint16_t aa_ms = ((uint16_t)lll->access_addr[3] << 8) |
-				      lll->access_addr[2];
-
 			lll->data_chan_sel = 1;
-			lll->data_chan_id = aa_ms ^ aa_ls;
+			lll->data_chan_id = lll_chan_id(lll->access_addr);
 
 			cs->csa = 0x01;
 		} else {
diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c
index 2edc5b34f191555961ec24c00f57bfd5172ab88d..636430cc7f9633e7b820c21664d99d5317f4a965 100644
--- a/subsys/bluetooth/controller/ll_sw/ull_sync.c
+++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c
@@ -24,6 +24,7 @@
 #include "lll.h"
 #include "lll_clock.h"
 #include "lll/lll_vendor.h"
+#include "lll_chan.h"
 #include "lll_scan.h"
 #include "lll_sync.h"
 #include "lll_sync_iso.h"
@@ -153,7 +154,6 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
 	lll_sync = &sync->lll;
 	lll_sync->skip_prepare = 0U;
 	lll_sync->skip_event = 0U;
-	lll_sync->data_chan_id = 0U;
 	lll_sync->window_widening_prepare_us = 0U;
 	lll_sync->window_widening_event_us = 0U;
 
@@ -376,6 +376,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
 	}
 
 	memcpy(lll->access_addr, &si->aa, sizeof(lll->access_addr));
+	lll->data_chan_id = lll_chan_id(lll->access_addr);
 	memcpy(lll->crc_init, si->crc_init, sizeof(lll->crc_init));
 	lll->event_counter = si->evt_cntr;
 	lll->phy = aux->lll.phy;
diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c
index deba3c6bff23fbdf4d05b3adebe42329967bef7f..b53e0a4c2db029faa0a87fa15ab9c786c8e1ce21 100644
--- a/subsys/bluetooth/host/conn.c
+++ b/subsys/bluetooth/host/conn.c
@@ -2345,7 +2345,7 @@ int bt_conn_le_create(const bt_addr_le_t *peer,
 	}
 
 	if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
-		return -EINVAL;
+		return -EAGAIN;
 	}
 
 	if (atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) {
diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c
index fe5f1e4ea7b66c25dd28e17f644b25b4a039bb09..e466b4f2a95bf1a74081e6a68d19252d1bd2abc5 100644
--- a/subsys/bluetooth/host/id.c
+++ b/subsys/bluetooth/host/id.c
@@ -194,7 +194,9 @@ static void le_rpa_invalidate(void)
 		atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID);
 	}
 
-	bt_le_ext_adv_foreach(adv_rpa_invalidate, NULL);
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER)) {
+		bt_le_ext_adv_foreach(adv_rpa_invalidate, NULL);
+	}
 }
 
 #if defined(CONFIG_BT_PRIVACY)
@@ -370,7 +372,8 @@ static void le_update_private_addr(void)
 	uint8_t id = BT_ID_DEFAULT;
 	int err;
 
-	if (IS_ENABLED(CONFIG_BT_EXT_ADV) &&
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER) &&
+	    IS_ENABLED(CONFIG_BT_EXT_ADV) &&
 	    BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) {
 		bt_le_ext_adv_foreach(adv_update_rpa, NULL);
 	}
@@ -395,7 +398,8 @@ static void le_update_private_addr(void)
 		bt_le_create_conn_cancel();
 	}
 
-	if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) &&
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER) &&
+	    !(IS_ENABLED(CONFIG_BT_EXT_ADV) &&
 	      BT_FEAT_LE_EXT_ADV(bt_dev.le.features))) {
 		adv = bt_le_adv_lookup_legacy();
 
@@ -418,7 +422,8 @@ static void le_update_private_addr(void)
 		return;
 	}
 
-	if (adv && adv_enabled) {
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER) &&
+	    adv && adv_enabled) {
 		bt_le_adv_set_enable_legacy(adv, true);
 	}
 
@@ -449,7 +454,9 @@ static void rpa_timeout(struct k_work *work)
 
 	le_rpa_invalidate();
 
-	bt_le_ext_adv_foreach(adv_is_private_enabled, &adv_enabled);
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER)) {
+		bt_le_ext_adv_foreach(adv_is_private_enabled, &adv_enabled);
+	}
 
 	/* IF no roles using the RPA is running we can stop the RPA timer */
 	if (!(adv_enabled ||
@@ -1050,11 +1057,6 @@ int bt_id_create(bt_addr_le_t *addr, uint8_t *irk)
 
 int bt_id_reset(uint8_t id, bt_addr_le_t *addr, uint8_t *irk)
 {
-	struct bt_adv_id_check_data check_data = {
-		.id = id,
-		.adv_enabled = false,
-	};
-
 	if (addr && bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
 		if (addr->type != BT_ADDR_LE_RANDOM ||
 		    !BT_ADDR_IS_STATIC(&addr->a)) {
@@ -1075,9 +1077,16 @@ int bt_id_reset(uint8_t id, bt_addr_le_t *addr, uint8_t *irk)
 		return -EINVAL;
 	}
 
-	bt_le_ext_adv_foreach(adv_id_check_func, &check_data);
-	if (check_data.adv_enabled) {
-		return -EBUSY;
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER)) {
+		struct bt_adv_id_check_data check_data = {
+			.id = id,
+			.adv_enabled = false,
+		};
+
+		bt_le_ext_adv_foreach(adv_id_check_func, &check_data);
+		if (check_data.adv_enabled) {
+			return -EBUSY;
+		}
 	}
 
 	if (IS_ENABLED(CONFIG_BT_CONN) &&
@@ -1097,11 +1106,6 @@ int bt_id_reset(uint8_t id, bt_addr_le_t *addr, uint8_t *irk)
 
 int bt_id_delete(uint8_t id)
 {
-	struct bt_adv_id_check_data check_data = {
-		.id = id,
-		.adv_enabled = false,
-	};
-
 	if (id == BT_ID_DEFAULT || id >= bt_dev.id_count) {
 		return -EINVAL;
 	}
@@ -1110,9 +1114,16 @@ int bt_id_delete(uint8_t id)
 		return -EALREADY;
 	}
 
-	bt_le_ext_adv_foreach(adv_id_check_func, &check_data);
-	if (check_data.adv_enabled) {
-		return -EBUSY;
+	if (IS_ENABLED(CONFIG_BT_BROADCASTER)) {
+		struct bt_adv_id_check_data check_data = {
+			.id = id,
+			.adv_enabled = false,
+		};
+
+		bt_le_ext_adv_foreach(adv_id_check_func, &check_data);
+		if (check_data.adv_enabled) {
+			return -EBUSY;
+		}
 	}
 
 	if (IS_ENABLED(CONFIG_BT_CONN)) {
diff --git a/subsys/debug/CMakeLists.txt b/subsys/debug/CMakeLists.txt
index 6e198cce9bb128d711d778adfc50265167b6c04e..4d2ed6c74713e6273c23be731c7a36d5f0039aa9 100644
--- a/subsys/debug/CMakeLists.txt
+++ b/subsys/debug/CMakeLists.txt
@@ -1,8 +1,14 @@
 # SPDX-License-Identifier: Apache-2.0
 
+if(CONFIG_OPENOCD_SUPPORT)
+  message(WARNING "CONFIG_OPENOCD_SUPPORT is deprecated
+  Please use DEBUG_THREAD_INFO instead."
+)
+endif()
+
 zephyr_sources_ifdef(
-  CONFIG_OPENOCD_SUPPORT
-  openocd.c
+  CONFIG_DEBUG_THREAD_INFO
+  thread_info.c
   )
 
 zephyr_sources_ifdef(
diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig
index 99f2b381102718d75b1ae32d8eaa821314eb7def..d538b44ed9e0b2ff2131f02476e494f9888258d0 100644
--- a/subsys/debug/Kconfig
+++ b/subsys/debug/Kconfig
@@ -332,16 +332,20 @@ config EXCEPTION_STACK_TRACE
 #
 # Miscellaneous debugging options
 #
-
 config OPENOCD_SUPPORT
-	bool "OpenOCD support [EXPERIMENTAL]"
+	bool "OpenOCD support (DEPRECATED)"
+	select DEBUG_THREAD_INFO
+	help
+	  This is deprecated, please use DEBUG_THREAD_INFO instead.
+
+config DEBUG_THREAD_INFO
+	bool "Thread awareness support"
 	depends on !SMP
 	select THREAD_MONITOR
 	select THREAD_NAME
 	help
-	  This option exports an array of offsets to kernel structs, used by
-	  OpenOCD to determine the state of running threads.  (This option
-	  selects CONFIG_THREAD_MONITOR, so all of its caveats are implied.)
+	  This option exports an array of offsets to kernel structs to allow
+	  for debugger RTOS plugins to determine the state of running threads.
 
 rsource "coredump/Kconfig"
 endmenu
diff --git a/subsys/debug/openocd.c b/subsys/debug/openocd.c
deleted file mode 100644
index 87cc0996c74a72e1f020ba172b53a81db9fe3bd5..0000000000000000000000000000000000000000
--- a/subsys/debug/openocd.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2017 Intel Corporation
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#include <kernel.h>
-
-#define OPENOCD_UNIMPLEMENTED	0xffffffff
-
-#if defined(CONFIG_OPENOCD_SUPPORT) && defined(CONFIG_THREAD_MONITOR)
-enum {
-	OPENOCD_OFFSET_VERSION,
-	OPENOCD_OFFSET_K_CURR_THREAD,
-	OPENOCD_OFFSET_K_THREADS,
-	OPENOCD_OFFSET_T_ENTRY,
-	OPENOCD_OFFSET_T_NEXT_THREAD,
-	OPENOCD_OFFSET_T_STATE,
-	OPENOCD_OFFSET_T_USER_OPTIONS,
-	OPENOCD_OFFSET_T_PRIO,
-	OPENOCD_OFFSET_T_STACK_PTR,
-	OPENOCD_OFFSET_T_NAME,
-	OPENOCD_OFFSET_T_ARCH,
-	OPENOCD_OFFSET_T_PREEMPT_FLOAT,
-	OPENOCD_OFFSET_T_COOP_FLOAT,
-};
-
-#if CONFIG_MP_NUM_CPUS > 1
-#error "This code doesn't work properly with multiple CPUs enabled"
-#endif
-
-/* Forward-compatibility notes: 1) Only append items to this table; otherwise
- * OpenOCD versions that expect less items will read garbage values.
- * 2) Avoid incompatible changes that affect the interpretation of existing
- * items. But if you have to do them, increment OPENOCD_OFFSET_VERSION
- * and submit a patch for OpenOCD to deal with both the old and new scheme.
- * Only version 1 is backward compatible to version 0.
- */
-__attribute__((used, section(".openocd_dbg")))
-size_t _kernel_openocd_offsets[] = {
-	/* Version 0 starts */
-	[OPENOCD_OFFSET_VERSION] = 1,
-	[OPENOCD_OFFSET_K_CURR_THREAD] = offsetof(struct _cpu, current),
-	[OPENOCD_OFFSET_K_THREADS] = offsetof(struct z_kernel, threads),
-	[OPENOCD_OFFSET_T_ENTRY] = offsetof(struct k_thread, entry),
-	[OPENOCD_OFFSET_T_NEXT_THREAD] = offsetof(struct k_thread, next_thread),
-	[OPENOCD_OFFSET_T_STATE] = offsetof(struct _thread_base, thread_state),
-	[OPENOCD_OFFSET_T_USER_OPTIONS] = offsetof(struct _thread_base,
-						   user_options),
-	[OPENOCD_OFFSET_T_PRIO] = offsetof(struct _thread_base, prio),
-#if defined(CONFIG_ARM64)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.sp),
-#elif defined(CONFIG_ARM)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.psp),
-#elif defined(CONFIG_ARC)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.sp),
-#elif defined(CONFIG_X86)
-#if defined(CONFIG_X86_64)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.rsp),
-#else
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.esp),
-#endif
-#elif defined(CONFIG_NIOS2)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.sp),
-#elif defined(CONFIG_RISCV)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.sp),
-#elif defined(CONFIG_SPARC)
-	[OPENOCD_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
-						callee_saved.o6),
-#else
-	/* Use a special value so that OpenOCD knows that obtaining the stack
-	 * pointer is not possible on this particular architecture.
-	 */
-#warning Please define OPENOCD_OFFSET_T_STACK_PTR for this architecture
-	[OPENOCD_OFFSET_T_STACK_PTR] = OPENOCD_UNIMPLEMENTED,
-#endif
-	/* Version 0 ends */
-
-	[OPENOCD_OFFSET_T_NAME] = offsetof(struct k_thread, name),
-	[OPENOCD_OFFSET_T_ARCH] = offsetof(struct k_thread, arch),
-#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) && defined(CONFIG_ARM)
-	[OPENOCD_OFFSET_T_PREEMPT_FLOAT] = offsetof(struct _thread_arch,
-						    preempt_float),
-	[OPENOCD_OFFSET_T_COOP_FLOAT] = OPENOCD_UNIMPLEMENTED,
-#elif defined(CONFIG_FPU) && defined(CONFIG_X86)
-#if defined(CONFIG_X86_64)
-	[OPENOCD_OFFSET_T_PREEMPT_FLOAT] = offsetof(struct _thread_arch, sse),
-#else
-	[OPENOCD_OFFSET_T_PREEMPT_FLOAT] = offsetof(struct _thread_arch,
-						    preempFloatReg),
-#endif
-	[OPENOCD_OFFSET_T_COOP_FLOAT] = OPENOCD_UNIMPLEMENTED,
-#else
-	[OPENOCD_OFFSET_T_PREEMPT_FLOAT] = OPENOCD_UNIMPLEMENTED,
-	[OPENOCD_OFFSET_T_COOP_FLOAT] = OPENOCD_UNIMPLEMENTED,
-#endif
-	/* Version is still 1, but existence of following elements must be
-	 * checked with _kernel_openocd_num_offsets.
-	 */
-};
-
-__attribute__((used, section(".openocd_dbg")))
-size_t _kernel_openocd_num_offsets = ARRAY_SIZE(_kernel_openocd_offsets);
-
-__attribute__((used, section(".openocd_dbg")))
-uint8_t _kernel_openocd_size_t_size = (uint8_t)sizeof(size_t);
-#endif
diff --git a/subsys/debug/thread_info.c b/subsys/debug/thread_info.c
new file mode 100644
index 0000000000000000000000000000000000000000..09cb37319ad317f043c9a980bf714bd875b464af
--- /dev/null
+++ b/subsys/debug/thread_info.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <kernel.h>
+
+#define THREAD_INFO_UNIMPLEMENTED	0xffffffff
+
+enum {
+	THREAD_INFO_OFFSET_VERSION,
+	THREAD_INFO_OFFSET_K_CURR_THREAD,
+	THREAD_INFO_OFFSET_K_THREADS,
+	THREAD_INFO_OFFSET_T_ENTRY,
+	THREAD_INFO_OFFSET_T_NEXT_THREAD,
+	THREAD_INFO_OFFSET_T_STATE,
+	THREAD_INFO_OFFSET_T_USER_OPTIONS,
+	THREAD_INFO_OFFSET_T_PRIO,
+	THREAD_INFO_OFFSET_T_STACK_PTR,
+	THREAD_INFO_OFFSET_T_NAME,
+	THREAD_INFO_OFFSET_T_ARCH,
+	THREAD_INFO_OFFSET_T_PREEMPT_FLOAT,
+	THREAD_INFO_OFFSET_T_COOP_FLOAT,
+};
+
+#if CONFIG_MP_NUM_CPUS > 1
+#error "This code doesn't work properly with multiple CPUs enabled"
+#endif
+
+/* Forward-compatibility notes: 1) Only append items to this table; otherwise
+ * debugger plugin versions that expect fewer items will read garbage values.
+ * 2) Avoid incompatible changes that affect the interpretation of existing
+ * items. But if you have to do them, increment THREAD_INFO_OFFSET_VERSION
+ * and submit a patch for debugger plugins to deal with both the old and new
+ * scheme.
+ * Only version 1 is backward compatible to version 0.
+ */
+__attribute__((used, section(".dbg_thread_info")))
+size_t _kernel_thread_info_offsets[] = {
+	/* Version 0 starts */
+	[THREAD_INFO_OFFSET_VERSION] = 1,
+	[THREAD_INFO_OFFSET_K_CURR_THREAD] = offsetof(struct _cpu, current),
+	[THREAD_INFO_OFFSET_K_THREADS] = offsetof(struct z_kernel, threads),
+	[THREAD_INFO_OFFSET_T_ENTRY] = offsetof(struct k_thread, entry),
+	[THREAD_INFO_OFFSET_T_NEXT_THREAD] = offsetof(struct k_thread,
+						      next_thread),
+	[THREAD_INFO_OFFSET_T_STATE] = offsetof(struct _thread_base,
+						thread_state),
+	[THREAD_INFO_OFFSET_T_USER_OPTIONS] = offsetof(struct _thread_base,
+						   user_options),
+	[THREAD_INFO_OFFSET_T_PRIO] = offsetof(struct _thread_base, prio),
+#if defined(CONFIG_ARM64)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.sp),
+#elif defined(CONFIG_ARM)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.psp),
+#elif defined(CONFIG_ARC)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.sp),
+#elif defined(CONFIG_X86)
+#if defined(CONFIG_X86_64)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.rsp),
+#else
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.esp),
+#endif
+#elif defined(CONFIG_NIOS2)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.sp),
+#elif defined(CONFIG_RISCV)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.sp),
+#elif defined(CONFIG_SPARC)
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = offsetof(struct k_thread,
+						callee_saved.o6),
+#else
+	/* Use a special value so that OpenOCD knows that obtaining the stack
+	 * pointer is not possible on this particular architecture.
+	 */
+#warning Please define THREAD_INFO_OFFSET_T_STACK_PTR for this architecture
+	[THREAD_INFO_OFFSET_T_STACK_PTR] = THREAD_INFO_UNIMPLEMENTED,
+#endif
+	/* Version 0 ends */
+
+	[THREAD_INFO_OFFSET_T_NAME] = offsetof(struct k_thread, name),
+	[THREAD_INFO_OFFSET_T_ARCH] = offsetof(struct k_thread, arch),
+#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) && defined(CONFIG_ARM)
+	[THREAD_INFO_OFFSET_T_PREEMPT_FLOAT] = offsetof(struct _thread_arch,
+						    preempt_float),
+	[THREAD_INFO_OFFSET_T_COOP_FLOAT] = THREAD_INFO_UNIMPLEMENTED,
+#elif defined(CONFIG_FPU) && defined(CONFIG_X86)
+#if defined(CONFIG_X86_64)
+	[THREAD_INFO_OFFSET_T_PREEMPT_FLOAT] = offsetof(struct _thread_arch,
+							sse),
+#else
+	[THREAD_INFO_OFFSET_T_PREEMPT_FLOAT] = offsetof(struct _thread_arch,
+						    preempFloatReg),
+#endif
+	[THREAD_INFO_OFFSET_T_COOP_FLOAT] = THREAD_INFO_UNIMPLEMENTED,
+#else
+	[THREAD_INFO_OFFSET_T_PREEMPT_FLOAT] = THREAD_INFO_UNIMPLEMENTED,
+	[THREAD_INFO_OFFSET_T_COOP_FLOAT] = THREAD_INFO_UNIMPLEMENTED,
+#endif
+	/* Version is still 1, but existence of following elements must be
+	 * checked with _kernel_thread_info_num_offsets.
+	 */
+};
+extern size_t __attribute__((alias("_kernel_thread_info_offsets")))
+		_kernel_openocd_offsets;
+
+__attribute__((used, section(".dbg_thread_info")))
+size_t _kernel_thread_info_num_offsets = ARRAY_SIZE(_kernel_thread_info_offsets);
+extern size_t __attribute__((alias("_kernel_thread_info_num_offsets")))
+		_kernel_openocd_num_offsets;
+
+__attribute__((used, section(".dbg_thread_info")))
+uint8_t _kernel_thread_info_size_t_size = (uint8_t)sizeof(size_t);
+extern uint8_t __attribute__((alias("_kernel_thread_info_size_t_size")))
+		_kernel_openocd_size_t_size;
diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c
index db89ba4e777db74c809508b347edfb98942209f6..9b0da4ceeb9e098571318c2d2eb87315cd984c6c 100644
--- a/subsys/net/ip/dhcpv4.c
+++ b/subsys/net/ip/dhcpv4.c
@@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(net_dhcpv4, CONFIG_NET_DHCPV4_LOG_LEVEL);
 static K_MUTEX_DEFINE(lock);
 
 static sys_slist_t dhcpv4_ifaces;
-static struct k_delayed_work timeout_work;
+static struct k_work_delayable timeout_work;
 
 static struct net_mgmt_event_callback mgmt4_cb;
 
@@ -278,14 +278,16 @@ fail:
 	return NULL;
 }
 
+/* Must be invoked with lock held. */
 static void dhcpv4_immediate_timeout(struct net_if_dhcpv4 *dhcpv4)
 {
 	NET_DBG("force timeout dhcpv4=%p", dhcpv4);
 	dhcpv4->timer_start = k_uptime_get() - 1;
 	dhcpv4->request_time = 0U;
-	k_delayed_work_submit(&timeout_work, K_NO_WAIT);
+	k_work_reschedule(&timeout_work, K_NO_WAIT);
 }
 
+/* Must be invoked with lock held. */
 static void dhcpv4_set_timeout(struct net_if_dhcpv4 *dhcpv4,
 			       uint32_t timeout)
 {
@@ -297,9 +299,10 @@ static void dhcpv4_set_timeout(struct net_if_dhcpv4 *dhcpv4,
 	 * event; also this timeout may replace the current timeout
 	 * event.  Delegate scheduling to the timeout manager.
 	 */
-	k_delayed_work_submit(&timeout_work, K_NO_WAIT);
+	k_work_reschedule(&timeout_work, K_NO_WAIT);
 }
 
+/* Must be invoked with lock held */
 static uint32_t dhcpv4_update_message_timeout(struct net_if_dhcpv4 *dhcpv4)
 {
 	uint32_t timeout;
@@ -526,6 +529,7 @@ static void dhcpv4_enter_requesting(struct net_if *iface)
 	dhcpv4_send_request(iface);
 }
 
+/* Must be invoked with lock held */
 static void dhcpv4_enter_bound(struct net_if *iface)
 {
 	uint32_t renewal_time;
@@ -653,8 +657,8 @@ static void dhcpv4_timeout(struct k_work *work)
 	if (timeout_update != UINT32_MAX) {
 		NET_DBG("Waiting for %us", timeout_update);
 
-		k_delayed_work_submit(&timeout_work,
-				      K_SECONDS(timeout_update));
+		k_work_reschedule(&timeout_work,
+				  K_SECONDS(timeout_update));
 	}
 }
 
@@ -900,6 +904,7 @@ static inline void dhcpv4_handle_msg_offer(struct net_if *iface)
 	}
 }
 
+/* Must be invoked with lock held */
 static void dhcpv4_handle_msg_ack(struct net_if *iface)
 {
 	switch (iface->config.dhcpv4.state) {
@@ -951,6 +956,7 @@ static void dhcpv4_handle_msg_nak(struct net_if *iface)
 	}
 }
 
+/* Takes and releases lock */
 static void dhcpv4_handle_reply(struct net_if *iface,
 				enum dhcpv4_msg_type msg_type)
 {
@@ -1226,7 +1232,10 @@ void net_dhcpv4_stop(struct net_if *iface)
 					  &iface->config.dhcpv4.node);
 
 		if (sys_slist_is_empty(&dhcpv4_ifaces)) {
-			k_delayed_work_cancel(&timeout_work);
+			/* Best effort cancel.  Handler is safe to invoke if
+			 * cancellation is unsuccessful.
+			 */
+			(void)k_work_cancel_delayable(&timeout_work);
 			net_mgmt_del_event_callback(&mgmt4_cb);
 		}
 
@@ -1262,7 +1271,7 @@ int net_dhcpv4_init(void)
 		return ret;
 	}
 
-	k_delayed_work_init(&timeout_work, dhcpv4_timeout);
+	k_work_init_delayable(&timeout_work, dhcpv4_timeout);
 
 	/* Catch network interface UP or DOWN events and renew the address
 	 * if interface is coming back up again.
diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c
index b546523204bdfa4754e7b15edc955374d6a04303..0adac8e30a0e1b105933aaa101145fde98377581 100644
--- a/subsys/net/ip/net_if.c
+++ b/subsys/net/ip/net_if.c
@@ -36,6 +36,8 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL);
 #define MAX_RANDOM_NUMER (3)
 #define MAX_RANDOM_DENOM (2)
 
+static K_MUTEX_DEFINE(lock);
+
 /* net_if dedicated section limiters */
 extern struct net_if _net_if_list_start[];
 extern struct net_if _net_if_list_end[];
@@ -398,16 +400,21 @@ void net_if_stats_reset(struct net_if *iface)
 			return;
 		}
 	}
+#else
+	ARG_UNUSED(iface);
 #endif
 }
 
 void net_if_stats_reset_all(void)
 {
 #if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
+	k_mutex_lock(&lock, K_FOREVER);
 
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
 		memset(&iface->stats, 0, sizeof(iface->stats));
 	}
+
+	k_mutex_unlock(&lock);
 #endif
 }
 
@@ -436,6 +443,8 @@ enum net_verdict net_if_send_data(struct net_if *iface, struct net_pkt *pkt)
 	enum net_verdict verdict = NET_OK;
 	int status = -EIO;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!net_if_flag_is_set(iface, NET_IF_UP) ||
 	    net_if_flag_is_set(iface, NET_IF_SUSPENDED)) {
 		/* Drop packet if interface is not up */
@@ -505,9 +514,26 @@ done:
 		net_if_queue_tx(iface, pkt);
 	}
 
+	k_mutex_unlock(&lock);
+
 	return verdict;
 }
 
+int net_if_set_link_addr_locked(struct net_if *iface,
+				uint8_t *addr, uint8_t len,
+				enum net_link_type type)
+{
+	int ret;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ret = net_if_set_link_addr_unlocked(iface, addr, len, type);
+
+	k_mutex_unlock(&lock);
+
+	return ret;
+}
+
 struct net_if *net_if_get_by_link_addr(struct net_linkaddr *ll_addr)
 {
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
@@ -624,8 +650,11 @@ static uint8_t get_ipaddr_diff(const uint8_t *src, const uint8_t *dst, int addr_
 static struct net_if_router *iface_router_lookup(struct net_if *iface,
 						 uint8_t family, void *addr)
 {
+	struct net_if_router *router = NULL;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
 		if (!routers[i].is_used ||
 		    routers[i].address.family != family ||
@@ -639,11 +668,15 @@ static struct net_if_router *iface_router_lookup(struct net_if *iface,
 		    (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET &&
 		     net_ipv4_addr_cmp(net_if_router_ipv4(&routers[i]),
 				       (struct in_addr *)addr))) {
-			return &routers[i];
+			router = &routers[i];
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return router;
 }
 
 static void iface_router_notify_deletion(struct net_if_router *router,
@@ -690,6 +723,8 @@ static void iface_router_update_timer(uint32_t now)
 	struct net_if_router *router, *next;
 	uint32_t new_delay = UINT32_MAX;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_router_timers,
 					 router, next, node) {
 		int32_t ends = iface_router_ends(router, now);
@@ -707,6 +742,8 @@ static void iface_router_update_timer(uint32_t now)
 	} else {
 		k_delayed_work_submit(&router_timer, K_MSEC(new_delay));
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 static void iface_router_expired(struct k_work *work)
@@ -717,6 +754,8 @@ static void iface_router_expired(struct k_work *work)
 
 	ARG_UNUSED(work);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_router_timers,
 					  router, next, node) {
 		int32_t ends = iface_router_ends(router, current_time);
@@ -736,6 +775,8 @@ static void iface_router_expired(struct k_work *work)
 	}
 
 	iface_router_update_timer(current_time);
+
+	k_mutex_unlock(&lock);
 }
 
 static struct net_if_router *iface_router_add(struct net_if *iface,
@@ -743,8 +784,11 @@ static struct net_if_router *iface_router_add(struct net_if *iface,
 					      bool is_default,
 					      uint16_t lifetime)
 {
+	struct net_if_router *router = NULL;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
 		if (routers[i].is_used) {
 			continue;
@@ -800,16 +844,24 @@ static struct net_if_router *iface_router_add(struct net_if *iface,
 				lifetime, is_default);
 		}
 
-		return &routers[i];
+		router = &routers[i];
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return router;
 }
 
 static bool iface_router_rm(struct net_if_router *router)
 {
+	bool ret = false;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!router->is_used) {
-		return false;
+		goto out;
 	}
 
 	iface_router_notify_deletion(router, "has been removed");
@@ -820,18 +872,36 @@ static bool iface_router_rm(struct net_if_router *router)
 	}
 
 	router->is_used = false;
+	ret = true;
 
-	return true;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
+}
+
+void net_if_router_rm(struct net_if_router *router)
+{
+	k_mutex_lock(&lock, K_FOREVER);
+
+	router->is_used = false;
+
+	/* FIXME - remove timer */
+
+	k_mutex_unlock(&lock);
 }
 
 static struct net_if_router *iface_router_find_default(struct net_if *iface,
 						       uint8_t family, void *addr)
 {
+	struct net_if_router *router = NULL;
 	int i;
 
 	/* Todo: addr will need to be handled */
 	ARG_UNUSED(addr);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	for (i = 0; i < CONFIG_NET_MAX_ROUTERS; i++) {
 		if (!routers[i].is_used ||
 		    !routers[i].is_default ||
@@ -843,10 +913,14 @@ static struct net_if_router *iface_router_find_default(struct net_if *iface,
 			continue;
 		}
 
-		return &routers[i];
+		router = &routers[i];
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return router;
 }
 
 static void iface_router_init(void)
@@ -861,14 +935,17 @@ static void iface_router_init(void)
 #if defined(CONFIG_NET_NATIVE_IPV6)
 int net_if_config_ipv6_get(struct net_if *iface, struct net_if_ipv6 **ipv6)
 {
+	int ret = 0;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (iface->config.ip.ipv6) {
 		if (ipv6) {
 			*ipv6 = iface->config.ip.ipv6;
 		}
 
-		return 0;
+		goto out;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(ipv6_addresses); i++) {
@@ -883,18 +960,26 @@ int net_if_config_ipv6_get(struct net_if *iface, struct net_if_ipv6 **ipv6)
 			*ipv6 = &ipv6_addresses[i].ipv6;
 		}
 
-		return 0;
+		goto out;
 	}
 
-	return -ESRCH;
+	ret = -ESRCH;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 int net_if_config_ipv6_put(struct net_if *iface)
 {
+	int ret = 0;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!iface->config.ip.ipv6) {
-		return -EALREADY;
+		ret = -EALREADY;
+		goto out;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(ipv6_addresses); i++) {
@@ -905,10 +990,14 @@ int net_if_config_ipv6_put(struct net_if *iface)
 		iface->config.ip.ipv6 = NULL;
 		ipv6_addresses[i].iface = NULL;
 
-		return 0;
+		goto out;
 	}
 
-	return -ESRCH;
+	ret = -ESRCH;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 #if defined(CONFIG_NET_IPV6_MLD)
@@ -992,6 +1081,8 @@ static void dad_timeout(struct k_work *work)
 
 	ARG_UNUSED(work);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_dad_timers,
 					  ifaddr, next, dad_node) {
 		struct net_if_addr *tmp;
@@ -1039,6 +1130,8 @@ static void dad_timeout(struct k_work *work)
 	if ((ifaddr != NULL) && (delay > 0)) {
 		k_delayed_work_submit(&dad_timer, K_MSEC((uint32_t)delay));
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 static void net_if_ipv6_start_dad(struct net_if *iface,
@@ -1082,15 +1175,17 @@ void net_if_start_dad(struct net_if *iface)
 	struct in6_addr addr = { };
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	NET_DBG("Starting DAD for iface %p", iface);
 
 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
 		NET_WARN("Cannot do DAD IPv6 config is not valid.");
-		return;
+		goto out;
 	}
 
 	if (!ipv6) {
-		return;
+		goto out;
 	}
 
 	net_ipv6_addr_create_iid(&addr, net_if_get_link_addr(iface));
@@ -1113,17 +1208,22 @@ void net_if_start_dad(struct net_if *iface)
 
 		net_if_ipv6_start_dad(iface, &ipv6->unicast[i]);
 	}
+
+out:
+	k_mutex_unlock(&lock);
 }
 
 void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
 {
 	struct net_if_addr *ifaddr;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	ifaddr = net_if_ipv6_addr_lookup(addr, &iface);
 	if (!ifaddr) {
 		NET_ERR("Cannot find %s address in interface %p",
 			log_strdup(net_sprint_ipv6_addr(addr)), iface);
-		return;
+		goto out;
 	}
 
 	sys_slist_find_and_remove(&active_dad_timers, &ifaddr->dad_node);
@@ -1133,6 +1233,9 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr)
 					sizeof(struct in6_addr));
 
 	net_if_ipv6_addr_rm(iface, addr);
+
+out:
+	k_mutex_unlock(&lock);
 }
 
 static inline void iface_ipv6_dad_init(void)
@@ -1163,6 +1266,8 @@ static void rs_timeout(struct k_work *work)
 
 	ARG_UNUSED(work);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_rs_timers,
 					  ipv6, next, rs_node) {
 		struct net_if *iface = NULL;
@@ -1206,14 +1311,19 @@ static void rs_timeout(struct k_work *work)
 				      K_MSEC(ipv6->rs_start +
 					     RS_TIMEOUT - current_time));
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_start_rs(struct net_if *iface)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	struct net_if_ipv6 *ipv6;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return;
+		goto out;
 	}
 
 	NET_DBG("Starting ND/RS for iface %p", iface);
@@ -1227,19 +1337,28 @@ void net_if_start_rs(struct net_if *iface)
 			k_delayed_work_submit(&rs_timer, K_MSEC(RS_TIMEOUT));
 		}
 	}
+
+out:
+	k_mutex_unlock(&lock);
 }
 
 void net_if_stop_rs(struct net_if *iface)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	struct net_if_ipv6 *ipv6;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return;
+		goto out;
 	}
 
 	NET_DBG("Stopping ND/RS for iface %p", iface);
 
 	sys_slist_find_and_remove(&active_rs_timers, &ipv6->rs_node);
+
+out:
+	k_mutex_unlock(&lock);
 }
 
 static inline void iface_ipv6_nd_init(void)
@@ -1257,6 +1376,10 @@ static inline void iface_ipv6_nd_init(void)
 struct net_if_addr *net_if_ipv6_addr_lookup(const struct in6_addr *addr,
 					    struct net_if **ret)
 {
+	struct net_if_addr *ifaddr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
 		struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
 		int i;
@@ -1280,22 +1403,30 @@ struct net_if_addr *net_if_ipv6_addr_lookup(const struct in6_addr *addr,
 					*ret = iface;
 				}
 
-				return &ipv6->unicast[i];
+				ifaddr = &ipv6->unicast[i];
+				goto out;
 			}
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifaddr;
 }
 
 struct net_if_addr *net_if_ipv6_addr_lookup_by_iface(struct net_if *iface,
 						     struct in6_addr *addr)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	struct net_if_addr *ifaddr = NULL;
+	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
@@ -1308,11 +1439,15 @@ struct net_if_addr *net_if_ipv6_addr_lookup_by_iface(struct net_if *iface,
 			    addr->s6_addr,
 			    ipv6->unicast[i].address.in6_addr.s6_addr,
 			    128)) {
-			return &ipv6->unicast[i];
+			ifaddr = &ipv6->unicast[i];
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifaddr;
 }
 
 int z_impl_net_if_ipv6_addr_lookup_by_index(const struct in6_addr *addr)
@@ -1362,6 +1497,8 @@ static void address_lifetime_timeout(struct k_work *work)
 
 	ARG_UNUSED(work);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_address_lifetime_timers,
 					  current, next, lifetime.node) {
 		struct net_timeout *timeout = &current->lifetime;
@@ -1388,6 +1525,8 @@ static void address_lifetime_timeout(struct k_work *work)
 		k_delayed_work_submit(&address_lifetime_timer,
 				      K_MSEC(next_update));
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 #if defined(CONFIG_NET_TEST)
@@ -1409,6 +1548,8 @@ static void address_start_timer(struct net_if_addr *ifaddr, uint32_t vlifetime)
 void net_if_ipv6_addr_update_lifetime(struct net_if_addr *ifaddr,
 				      uint32_t vlifetime)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	NET_DBG("Updating expire time of %s by %u secs",
 		log_strdup(net_sprint_ipv6_addr(&ifaddr->address.in6_addr)),
 		vlifetime);
@@ -1416,6 +1557,8 @@ void net_if_ipv6_addr_update_lifetime(struct net_if_addr *ifaddr,
 	ifaddr->addr_state = NET_ADDR_PREFERRED;
 
 	address_start_timer(ifaddr, vlifetime);
+
+	k_mutex_unlock(&lock);
 }
 
 static struct net_if_addr *ipv6_addr_find(struct net_if *iface,
@@ -1469,17 +1612,19 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
 					 enum net_addr_type addr_type,
 					 uint32_t vlifetime)
 {
-	struct net_if_addr *ifaddr;
+	struct net_if_addr *ifaddr = NULL;
 	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
-		return NULL;
+		goto out;
 	}
 
 	ifaddr = ipv6_addr_find(iface, addr);
 	if (ifaddr) {
-		return ifaddr;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
@@ -1516,21 +1661,29 @@ struct net_if_addr *net_if_ipv6_addr_add(struct net_if *iface,
 			&ipv6->unicast[i].address.in6_addr,
 			sizeof(struct in6_addr));
 
-		return &ipv6->unicast[i];
+		ifaddr = &ipv6->unicast[i];
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifaddr;
 }
 
 bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	bool ret = false;
+	struct net_if_ipv6 *ipv6;
 	int i;
 
 	NET_ASSERT(addr);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return false;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
@@ -1576,10 +1729,14 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr)
 			&ipv6->unicast[i].address.in6_addr,
 			sizeof(struct in6_addr));
 
-		return true;
+		ret = true;
+		goto out;
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 bool z_impl_net_if_ipv6_addr_add_by_index(int index,
@@ -1659,23 +1816,26 @@ bool z_vrfy_net_if_ipv6_addr_rm_by_index(int index,
 struct net_if_mcast_addr *net_if_ipv6_maddr_add(struct net_if *iface,
 						const struct in6_addr *addr)
 {
+	struct net_if_mcast_addr *ifmaddr = NULL;
 	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
-		return NULL;
+		goto out;
 	}
 
 	if (!net_ipv6_is_addr_mcast(addr)) {
 		NET_DBG("Address %s is not a multicast address.",
 			log_strdup(net_sprint_ipv6_addr(addr)));
-		return NULL;
+		goto out;
 	}
 
 	if (net_if_ipv6_maddr_lookup(addr, &iface)) {
 		NET_WARN("Multicast address %s is is already registered.",
 			log_strdup(net_sprint_ipv6_addr(addr)));
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
@@ -1695,19 +1855,27 @@ struct net_if_mcast_addr *net_if_ipv6_maddr_add(struct net_if *iface,
 			&ipv6->mcast[i].address.in6_addr,
 			sizeof(struct in6_addr));
 
-		return &ipv6->mcast[i];
+		ifmaddr = &ipv6->mcast[i];
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifmaddr;
 }
 
 bool net_if_ipv6_maddr_rm(struct net_if *iface, const struct in6_addr *addr)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	bool ret = false;
+	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return false;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
@@ -1730,15 +1898,23 @@ bool net_if_ipv6_maddr_rm(struct net_if *iface, const struct in6_addr *addr)
 			&ipv6->mcast[i].address.in6_addr,
 			sizeof(struct in6_addr));
 
-		return true;
+		ret = true;
+		goto out;
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *maddr,
 						   struct net_if **ret)
 {
+	struct net_if_mcast_addr *ifmaddr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
 		struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
 		int i;
@@ -1765,28 +1941,62 @@ struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *maddr,
 					*ret = iface;
 				}
 
-				return &ipv6->mcast[i];
+				ifmaddr = &ipv6->mcast[i];
+				goto out;
 			}
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifmaddr;
+}
+
+void net_if_ipv6_maddr_leave(struct net_if_mcast_addr *addr)
+{
+	NET_ASSERT(addr);
+
+	k_mutex_lock(&lock, K_FOREVER);
+
+	addr->is_joined = false;
+
+	k_mutex_unlock(&lock);
+}
+
+void net_if_ipv6_maddr_join(struct net_if_mcast_addr *addr)
+{
+	NET_ASSERT(addr);
+
+	k_mutex_lock(&lock, K_FOREVER);
+
+	addr->is_joined = true;
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_mcast_mon_register(struct net_if_mcast_monitor *mon,
 			       struct net_if *iface,
 			       net_if_mcast_callback_t cb)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	sys_slist_find_and_remove(&mcast_monitor_callbacks, &mon->node);
 	sys_slist_prepend(&mcast_monitor_callbacks, &mon->node);
 
 	mon->iface = iface;
 	mon->cb = cb;
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_mcast_mon_unregister(struct net_if_mcast_monitor *mon)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	sys_slist_find_and_remove(&mcast_monitor_callbacks, &mon->node);
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_mcast_monitor(struct net_if *iface,
@@ -1795,12 +2005,16 @@ void net_if_mcast_monitor(struct net_if *iface,
 {
 	struct net_if_mcast_monitor *mon, *tmp;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&mcast_monitor_callbacks,
 					  mon, tmp, node) {
 		if (iface == mon->iface) {
 			mon->cb(iface, addr, is_joined);
 		}
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 static void remove_prefix_addresses(struct net_if *iface,
@@ -1853,6 +2067,8 @@ static void prefix_lifetime_expired(struct net_if_ipv6_prefix *ifprefix)
 
 static void prefix_timer_remove(struct net_if_ipv6_prefix *ifprefix)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	NET_DBG("IPv6 prefix %s/%d removed",
 		log_strdup(net_sprint_ipv6_addr(&ifprefix->prefix)),
 		ifprefix->len);
@@ -1861,6 +2077,8 @@ static void prefix_timer_remove(struct net_if_ipv6_prefix *ifprefix)
 				  &ifprefix->lifetime.node);
 
 	net_timeout_set(&ifprefix->lifetime, 0, 0);
+
+	k_mutex_unlock(&lock);
 }
 
 static void prefix_lifetime_timeout(struct k_work *work)
@@ -1871,6 +2089,8 @@ static void prefix_lifetime_timeout(struct k_work *work)
 
 	ARG_UNUSED(work);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_prefix_lifetime_timers,
 					  current, next, lifetime.node) {
 		struct net_timeout *timeout = &current->lifetime;
@@ -1895,11 +2115,15 @@ static void prefix_lifetime_timeout(struct k_work *work)
 		k_delayed_work_submit(&prefix_lifetime_timer,
 				      K_MSEC(next_update));
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 static void prefix_start_timer(struct net_if_ipv6_prefix *ifprefix,
 			       uint32_t lifetime)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	(void)sys_slist_find_and_remove(&active_prefix_lifetime_timers,
 					&ifprefix->lifetime.node);
 	sys_slist_append(&active_prefix_lifetime_timers,
@@ -1907,6 +2131,8 @@ static void prefix_start_timer(struct net_if_ipv6_prefix *ifprefix,
 
 	net_timeout_set(&ifprefix->lifetime, lifetime, k_uptime_get_32());
 	k_delayed_work_submit(&prefix_lifetime_timer, K_NO_WAIT);
+
+	k_mutex_unlock(&lock);
 }
 
 static struct net_if_ipv6_prefix *ipv6_prefix_find(struct net_if *iface,
@@ -1956,21 +2182,23 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_add(struct net_if *iface,
 						  uint8_t len,
 						  uint32_t lifetime)
 {
-	struct net_if_ipv6_prefix *ifprefix;
+	struct net_if_ipv6_prefix *ifprefix = NULL;
 	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
-		return NULL;
+		goto out;
 	}
 
 	ifprefix = ipv6_prefix_find(iface, prefix, len);
 	if (ifprefix) {
-		return ifprefix;
+		goto out;
 	}
 
 	if (!ipv6) {
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
@@ -1988,20 +2216,28 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_add(struct net_if *iface,
 			NET_EVENT_IPV6_PREFIX_ADD, iface,
 			&ipv6->prefix[i].prefix, sizeof(struct in6_addr));
 
-		return &ipv6->prefix[i];
+		ifprefix = &ipv6->prefix[i];
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifprefix;
 }
 
 bool net_if_ipv6_prefix_rm(struct net_if *iface, struct in6_addr *addr,
 			   uint8_t len)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	bool ret = false;
+	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return false;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
@@ -2027,10 +2263,14 @@ bool net_if_ipv6_prefix_rm(struct net_if *iface, struct in6_addr *addr,
 			NET_EVENT_IPV6_PREFIX_DEL, iface,
 			&ipv6->prefix[i].prefix, sizeof(struct in6_addr));
 
-		return true;
+		ret = true;
+		goto out;
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface,
@@ -2040,13 +2280,15 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface,
 	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!iface) {
 		iface = net_if_get_default();
 	}
 
 	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
@@ -2063,6 +2305,9 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_get(struct net_if *iface,
 		}
 	}
 
+out:
+	k_mutex_unlock(&lock);
+
 	return prefix;
 }
 
@@ -2070,11 +2315,15 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_lookup(struct net_if *iface,
 						     struct in6_addr *addr,
 						     uint8_t len)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	struct net_if_ipv6_prefix *prefix = NULL;
+	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_PREFIX; i++) {
@@ -2084,15 +2333,23 @@ struct net_if_ipv6_prefix *net_if_ipv6_prefix_lookup(struct net_if *iface,
 
 		if (net_ipv6_is_prefix(ipv6->prefix[i].prefix.s6_addr,
 				       addr->s6_addr, len)) {
-			return &ipv6->prefix[i];
+			prefix = &ipv6->prefix[i];
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return prefix;
 }
 
 bool net_if_ipv6_addr_onlink(struct net_if **iface, struct in6_addr *addr)
 {
+	bool ret = false;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	Z_STRUCT_SECTION_FOREACH(net_if, tmp) {
 		struct net_if_ipv6 *ipv6 = tmp->config.ip.ipv6;
 		int i;
@@ -2114,12 +2371,16 @@ bool net_if_ipv6_addr_onlink(struct net_if **iface, struct in6_addr *addr)
 					*iface = tmp;
 				}
 
-				return true;
+				ret = true;
+				goto out;
 			}
 		}
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 void net_if_ipv6_prefix_set_timer(struct net_if_ipv6_prefix *prefix,
@@ -2184,11 +2445,15 @@ bool net_if_ipv6_router_rm(struct net_if_router *router)
 struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
 				    enum net_addr_state addr_state)
 {
-	struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
+	struct in6_addr *addr = NULL;
+	struct net_if_ipv6 *ipv6;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv6 = iface->config.ip.ipv6;
 	if (!ipv6) {
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
@@ -2200,30 +2465,39 @@ struct in6_addr *net_if_ipv6_get_ll(struct net_if *iface,
 		}
 
 		if (net_ipv6_is_ll_addr(&ipv6->unicast[i].address.in6_addr)) {
-			return &ipv6->unicast[i].address.in6_addr;
+			addr = &ipv6->unicast[i].address.in6_addr;
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return addr;
 }
 
 struct in6_addr *net_if_ipv6_get_ll_addr(enum net_addr_state state,
 					 struct net_if **iface)
 {
-	Z_STRUCT_SECTION_FOREACH(net_if, tmp) {
-		struct in6_addr *addr;
+	struct in6_addr *addr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
+	Z_STRUCT_SECTION_FOREACH(net_if, tmp) {
 		addr = net_if_ipv6_get_ll(tmp, state);
 		if (addr) {
 			if (iface) {
 				*iface = tmp;
 			}
 
-			return addr;
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return addr;
 }
 
 static inline struct in6_addr *check_global_addr(struct net_if *iface,
@@ -2254,9 +2528,11 @@ static inline struct in6_addr *check_global_addr(struct net_if *iface,
 struct in6_addr *net_if_ipv6_get_global_addr(enum net_addr_state state,
 					     struct net_if **iface)
 {
-	Z_STRUCT_SECTION_FOREACH(net_if, tmp) {
-		struct in6_addr *addr;
+	struct in6_addr *addr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
+	Z_STRUCT_SECTION_FOREACH(net_if, tmp) {
 		if (iface && *iface && tmp != *iface) {
 			continue;
 		}
@@ -2267,11 +2543,14 @@ struct in6_addr *net_if_ipv6_get_global_addr(enum net_addr_state state,
 				*iface = tmp;
 			}
 
-			return addr;
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return addr;
 }
 
 static uint8_t get_diff_ipv6(const struct in6_addr *src,
@@ -2330,9 +2609,11 @@ static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
 const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface,
 						   const struct in6_addr *dst)
 {
-	struct in6_addr *src = NULL;
+	const struct in6_addr *src = NULL;
 	uint8_t best_match = 0U;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!net_ipv6_is_ll_addr(dst) && (!net_ipv6_is_addr_mcast(dst) ||
 	    net_ipv6_is_addr_mcast_mesh(dst))) {
 
@@ -2370,26 +2651,34 @@ const struct in6_addr *net_if_ipv6_select_src_addr(struct net_if *dst_iface,
 	}
 
 	if (!src) {
-		return net_ipv6_unspecified_address();
+		src = net_ipv6_unspecified_address();
+		goto out;
 	}
 
+out:
+	k_mutex_unlock(&lock);
+
 	return src;
 }
 
 struct net_if *net_if_ipv6_select_src_iface(const struct in6_addr *dst)
 {
+	struct net_if *iface = NULL;
 	const struct in6_addr *src;
-	struct net_if *iface;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
 	src = net_if_ipv6_select_src_addr(NULL, dst);
-	if (src == net_ipv6_unspecified_address()) {
-		return net_if_get_default();
+	if (src != net_ipv6_unspecified_address()) {
+		net_if_ipv6_addr_lookup(src, &iface);
 	}
 
-	if (!net_if_ipv6_addr_lookup(src, &iface)) {
-		return net_if_get_default();
+	if (iface == NULL) {
+		iface = net_if_get_default();
 	}
 
+	k_mutex_unlock(&lock);
+
 	return iface;
 }
 
@@ -2397,11 +2686,15 @@ uint32_t net_if_ipv6_calc_reachable_time(struct net_if_ipv6 *ipv6)
 {
 	uint32_t min_reachable, max_reachable;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	min_reachable = (MIN_RANDOM_NUMER * ipv6->base_reachable_time)
 			/ MIN_RANDOM_DENOM;
 	max_reachable = (MAX_RANDOM_NUMER * ipv6->base_reachable_time)
 			/ MAX_RANDOM_DENOM;
 
+	k_mutex_unlock(&lock);
+
 	NET_DBG("min_reachable:%u max_reachable:%u", min_reachable,
 		max_reachable);
 
@@ -2488,14 +2781,17 @@ struct in6_addr *net_if_ipv6_get_global_addr(enum net_addr_state state,
 #if defined(CONFIG_NET_NATIVE_IPV4)
 int net_if_config_ipv4_get(struct net_if *iface, struct net_if_ipv4 **ipv4)
 {
+	int ret = 0;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (iface->config.ip.ipv4) {
 		if (ipv4) {
 			*ipv4 = iface->config.ip.ipv4;
 		}
 
-		return 0;
+		goto out;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) {
@@ -2510,18 +2806,26 @@ int net_if_config_ipv4_get(struct net_if *iface, struct net_if_ipv4 **ipv4)
 			*ipv4 = &ipv4_addresses[i].ipv4;
 		}
 
-		return 0;
+		goto out;
 	}
 
-	return -ESRCH;
+	ret = -ESRCH;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 int net_if_config_ipv4_put(struct net_if *iface)
 {
+	int ret = 0;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!iface->config.ip.ipv4) {
-		return -EALREADY;
+		ret = -EALREADY;
+		goto out;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(ipv4_addresses); i++) {
@@ -2532,10 +2836,14 @@ int net_if_config_ipv4_put(struct net_if *iface)
 		iface->config.ip.ipv4 = NULL;
 		ipv4_addresses[i].iface = NULL;
 
-		return 0;
+		goto out;
 	}
 
-	return 0;
+	ret = -ESRCH;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 struct net_if_router *net_if_ipv4_router_lookup(struct net_if *iface,
@@ -2566,12 +2874,16 @@ bool net_if_ipv4_router_rm(struct net_if_router *router)
 bool net_if_ipv4_addr_mask_cmp(struct net_if *iface,
 			       const struct in_addr *addr)
 {
-	struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
+	bool ret = false;
+	struct net_if_ipv4 *ipv4;
 	uint32_t subnet;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv4 = iface->config.ip.ipv4;
 	if (!ipv4) {
-		return false;
+		goto out;
 	}
 
 	subnet = UNALIGNED_GET(&addr->s_addr) & ipv4->netmask.s_addr;
@@ -2584,11 +2896,15 @@ bool net_if_ipv4_addr_mask_cmp(struct net_if *iface,
 
 		if ((ipv4->unicast[i].address.in_addr.s_addr &
 		     ipv4->netmask.s_addr) == subnet) {
-			return true;
+			ret = true;
+			goto out;
 		}
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 static bool ipv4_is_broadcast_address(struct net_if *iface,
@@ -2615,34 +2931,52 @@ static bool ipv4_is_broadcast_address(struct net_if *iface,
 bool net_if_ipv4_is_addr_bcast(struct net_if *iface,
 			       const struct in_addr *addr)
 {
+	bool ret = false;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (iface) {
-		return ipv4_is_broadcast_address(iface, addr);
+		ret = ipv4_is_broadcast_address(iface, addr);
+		goto out;
 	}
 
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
-		bool ret;
-
 		ret = ipv4_is_broadcast_address(iface, addr);
 		if (ret) {
-			return ret;
+			goto out;
 		}
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 struct net_if *net_if_ipv4_select_src_iface(const struct in_addr *dst)
 {
+	struct net_if *selected = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
 		bool ret;
 
 		ret = net_if_ipv4_addr_mask_cmp(iface, dst);
 		if (ret) {
-			return iface;
+			selected = iface;
+			goto out;
 		}
 	}
 
-	return net_if_get_default();
+	if (selected == NULL) {
+		selected = net_if_get_default();
+	}
+
+out:
+	k_mutex_unlock(&lock);
+
+	return selected;
 }
 
 static uint8_t get_diff_ipv4(const struct in_addr *src,
@@ -2693,16 +3027,19 @@ static struct in_addr *net_if_ipv4_get_best_match(struct net_if *iface,
 static struct in_addr *if_ipv4_get_addr(struct net_if *iface,
 					enum net_addr_state addr_state, bool ll)
 {
+	struct in_addr *addr = NULL;
 	struct net_if_ipv4 *ipv4;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!iface) {
-		return NULL;
+		goto out;
 	}
 
 	ipv4 = iface->config.ip.ipv4;
 	if (!ipv4) {
-		return NULL;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
@@ -2723,10 +3060,14 @@ static struct in_addr *if_ipv4_get_addr(struct net_if *iface,
 			}
 		}
 
-		return &ipv4->unicast[i].address.in_addr;
+		addr = &ipv4->unicast[i].address.in_addr;
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return addr;
 }
 
 struct in_addr *net_if_ipv4_get_ll(struct net_if *iface,
@@ -2744,9 +3085,11 @@ struct in_addr *net_if_ipv4_get_global_addr(struct net_if *iface,
 const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *dst_iface,
 						  const struct in_addr *dst)
 {
-	struct in_addr *src = NULL;
+	const struct in_addr *src = NULL;
 	uint8_t best_match = 0U;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!net_ipv4_is_ll_addr(dst) && !net_ipv4_is_addr_mcast(dst)) {
 
 		/* If caller has supplied interface, then use that */
@@ -2785,19 +3128,26 @@ const struct in_addr *net_if_ipv4_select_src_addr(struct net_if *dst_iface,
 	if (!src) {
 		src = net_if_ipv4_get_global_addr(dst_iface,
 						  NET_ADDR_PREFERRED);
-		if (src) {
-			return src;
+		if (!src) {
+			src = net_ipv4_unspecified_address();
 		}
 
-		return net_ipv4_unspecified_address();
+		goto out;
 	}
 
+out:
+	k_mutex_unlock(&lock);
+
 	return src;
 }
 
 struct net_if_addr *net_if_ipv4_addr_lookup(const struct in_addr *addr,
 					    struct net_if **ret)
 {
+	struct net_if_addr *ifaddr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
 		struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
 		int i;
@@ -2819,12 +3169,16 @@ struct net_if_addr *net_if_ipv4_addr_lookup(const struct in_addr *addr,
 					*ret = iface;
 				}
 
-				return &ipv4->unicast[i];
+				ifaddr = &ipv4->unicast[i];
+				goto out;
 			}
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifaddr;
 }
 
 int z_impl_net_if_ipv4_addr_lookup_by_index(const struct in_addr *addr)
@@ -2856,15 +3210,19 @@ static inline int z_vrfy_net_if_ipv4_addr_lookup_by_index(
 void net_if_ipv4_set_netmask(struct net_if *iface,
 			     const struct in_addr *netmask)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_config_ipv4_get(iface, NULL) < 0) {
-		return;
+		goto out;
 	}
 
 	if (!iface->config.ip.ipv4) {
-		return;
+		goto out;
 	}
 
 	net_ipaddr_copy(&iface->config.ip.ipv4->netmask, netmask);
+out:
+	k_mutex_unlock(&lock);
 }
 
 bool z_impl_net_if_ipv4_set_netmask_by_index(int index,
@@ -2905,15 +3263,19 @@ bool z_vrfy_net_if_ipv4_set_netmask_by_index(int index,
 
 void net_if_ipv4_set_gw(struct net_if *iface, const struct in_addr *gw)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_config_ipv4_get(iface, NULL) < 0) {
-		return;
+		goto out;
 	}
 
 	if (!iface->config.ip.ipv4) {
-		return;
+		goto out;
 	}
 
 	net_ipaddr_copy(&iface->config.ip.ipv4->gw, gw);
+out:
+	k_mutex_unlock(&lock);
 }
 
 bool z_impl_net_if_ipv4_set_gw_by_index(int index,
@@ -2976,18 +3338,20 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
 					 enum net_addr_type addr_type,
 					 uint32_t vlifetime)
 {
-	struct net_if_addr *ifaddr;
+	struct net_if_addr *ifaddr = NULL;
 	struct net_if_ipv4 *ipv4;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_config_ipv4_get(iface, &ipv4) < 0) {
-		return NULL;
+		goto out;
 	}
 
 	ifaddr = ipv4_addr_find(iface, addr);
 	if (ifaddr) {
 		/* TODO: should set addr_type/vlifetime */
-		return ifaddr;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
@@ -3032,20 +3396,26 @@ struct net_if_addr *net_if_ipv4_addr_add(struct net_if *iface,
 		net_mgmt_event_notify_with_info(NET_EVENT_IPV4_ADDR_ADD, iface,
 						&ifaddr->address.in_addr,
 						sizeof(struct in_addr));
-
-		return ifaddr;
+		goto out;
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return ifaddr;
 }
 
 bool net_if_ipv4_addr_rm(struct net_if *iface, const struct in_addr *addr)
 {
-	struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
+	struct net_if_ipv4 *ipv4;
+	bool ret = false;
 	int i;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
+	ipv4 = iface->config.ip.ipv4;
 	if (!ipv4) {
-		return false;
+		goto out;
 	}
 
 	for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
@@ -3068,10 +3438,14 @@ bool net_if_ipv4_addr_rm(struct net_if *iface, const struct in_addr *addr)
 			&ipv4->unicast[i].address.in_addr,
 			sizeof(struct in_addr));
 
-		return true;
+		ret = true;
+		goto out;
 	}
 
-	return false;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 bool z_impl_net_if_ipv4_addr_add_by_index(int index,
@@ -3181,16 +3555,18 @@ static struct net_if_mcast_addr *ipv4_maddr_find(struct net_if *iface,
 struct net_if_mcast_addr *net_if_ipv4_maddr_add(struct net_if *iface,
 						const struct in_addr *addr)
 {
-	struct net_if_mcast_addr *maddr;
+	struct net_if_mcast_addr *maddr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
 	if (net_if_config_ipv4_get(iface, NULL) < 0) {
-		return NULL;
+		goto out;
 	}
 
 	if (!net_ipv4_is_addr_mcast(addr)) {
 		NET_DBG("Address %s is not a multicast address.",
 			log_strdup(net_sprint_ipv4_addr(addr)));
-		return NULL;
+		goto out;
 	}
 
 	maddr = ipv4_maddr_find(iface, false, NULL);
@@ -3203,12 +3579,18 @@ struct net_if_mcast_addr *net_if_ipv4_maddr_add(struct net_if *iface,
 			log_strdup(net_sprint_ipv4_addr(addr)));
 	}
 
+out:
+	k_mutex_unlock(&lock);
+
 	return maddr;
 }
 
 bool net_if_ipv4_maddr_rm(struct net_if *iface, const struct in_addr *addr)
 {
 	struct net_if_mcast_addr *maddr;
+	bool ret = false;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
 	maddr = ipv4_maddr_find(iface, true, addr);
 	if (maddr) {
@@ -3217,16 +3599,20 @@ bool net_if_ipv4_maddr_rm(struct net_if *iface, const struct in_addr *addr)
 		NET_DBG("interface %p address %s removed",
 			iface, log_strdup(net_sprint_ipv4_addr(addr)));
 
-		return true;
+		ret = true;
 	}
 
-	return false;
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 struct net_if_mcast_addr *net_if_ipv4_maddr_lookup(const struct in_addr *maddr,
 						   struct net_if **ret)
 {
-	struct net_if_mcast_addr *addr;
+	struct net_if_mcast_addr *addr = NULL;
+
+	k_mutex_lock(&lock, K_FOREVER);
 
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
 		if (ret && *ret && iface != *ret) {
@@ -3239,11 +3625,14 @@ struct net_if_mcast_addr *net_if_ipv4_maddr_lookup(const struct in_addr *maddr,
 				*ret = iface;
 			}
 
-			return addr;
+			goto out;
 		}
 	}
 
-	return NULL;
+out:
+	k_mutex_unlock(&lock);
+
+	return addr;
 }
 
 static void iface_ipv4_init(int if_count)
@@ -3296,32 +3685,32 @@ struct in_addr *net_if_ipv4_get_global_addr(struct net_if *iface,
 
 struct net_if *net_if_select_src_iface(const struct sockaddr *dst)
 {
-	struct net_if *iface;
+	struct net_if *iface = NULL;
 
 	if (!dst) {
 		goto out;
 	}
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (IS_ENABLED(CONFIG_NET_IPV6) && dst->sa_family == AF_INET6) {
 		iface = net_if_ipv6_select_src_iface(&net_sin6(dst)->sin6_addr);
-		if (!iface) {
-			goto out;
-		}
-
-		return iface;
+		goto out;
 	}
 
 	if (IS_ENABLED(CONFIG_NET_IPV4) && dst->sa_family == AF_INET) {
 		iface = net_if_ipv4_select_src_iface(&net_sin(dst)->sin_addr);
-		if (!iface) {
-			goto out;
-		}
-
-		return iface;
+		goto out;
 	}
 
 out:
-	return net_if_get_default();
+	k_mutex_unlock(&lock);
+
+	if (iface == NULL) {
+		iface = net_if_get_default();
+	}
+
+	return iface;
 }
 
 enum net_verdict net_if_recv_data(struct net_if *iface, struct net_pkt *pkt)
@@ -3372,15 +3761,23 @@ enum net_verdict net_if_recv_data(struct net_if *iface, struct net_pkt *pkt)
 void net_if_register_link_cb(struct net_if_link_cb *link,
 			     net_if_link_callback_t cb)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	sys_slist_find_and_remove(&link_callbacks, &link->node);
 	sys_slist_prepend(&link_callbacks, &link->node);
 
 	link->cb = cb;
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_unregister_link_cb(struct net_if_link_cb *link)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	sys_slist_find_and_remove(&link_callbacks, &link->node);
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_call_link_cb(struct net_if *iface, struct net_linkaddr *lladdr,
@@ -3388,9 +3785,13 @@ void net_if_call_link_cb(struct net_if *iface, struct net_linkaddr *lladdr,
 {
 	struct net_if_link_cb *link, *tmp;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&link_callbacks, link, tmp, node) {
 		link->cb(iface, lladdr, status);
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 static bool need_calc_checksum(struct net_if *iface, enum ethernet_hw_caps caps)
@@ -3402,6 +3803,9 @@ static bool need_calc_checksum(struct net_if *iface, enum ethernet_hw_caps caps)
 
 	return !(net_eth_get_hw_capabilities(iface) & caps);
 #else
+	ARG_UNUSED(iface);
+	ARG_UNUSED(caps);
+
 	return true;
 #endif
 }
@@ -3434,12 +3838,15 @@ void net_if_foreach(net_if_cb_t cb, void *user_data)
 
 int net_if_up(struct net_if *iface)
 {
-	int status;
+	int status = 0;
 
 	NET_DBG("iface %p", iface);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_flag_is_set(iface, NET_IF_UP)) {
-		return 0;
+		status = -EALREADY;
+		goto out;
 	}
 
 	if ((IS_ENABLED(CONFIG_NET_OFFLOAD) &&
@@ -3447,7 +3854,7 @@ int net_if_up(struct net_if *iface)
 	    (IS_ENABLED(CONFIG_NET_SOCKETS_OFFLOAD) &&
 	     net_if_is_socket_offloaded(iface))) {
 		net_if_flag_set(iface, NET_IF_UP);
-		goto exit;
+		goto notify;
 	}
 
 	/* If the L2 does not support enable just set the flag */
@@ -3458,7 +3865,7 @@ int net_if_up(struct net_if *iface)
 	/* Notify L2 to enable the interface */
 	status = net_if_l2(iface)->enable(iface, true);
 	if (status < 0) {
-		return status;
+		goto out;
 	}
 
 done:
@@ -3478,29 +3885,38 @@ done:
 		net_ipv4_autoconf_start(iface);
 	}
 
-exit:
+notify:
 	net_mgmt_event_notify(NET_EVENT_IF_UP, iface);
 
-	return 0;
+out:
+	k_mutex_unlock(&lock);
+
+	return status;
 }
 
 void net_if_carrier_down(struct net_if *iface)
 {
 	NET_DBG("iface %p", iface);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	net_if_flag_clear(iface, NET_IF_UP);
 
 	net_ipv4_autoconf_reset(iface);
 
 	net_mgmt_event_notify(NET_EVENT_IF_DOWN, iface);
+
+	k_mutex_unlock(&lock);
 }
 
 int net_if_down(struct net_if *iface)
 {
-	int status;
+	int status = 0;
 
 	NET_DBG("iface %p", iface);
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	leave_mcast_all(iface);
 
 	if (net_if_is_ip_offloaded(iface)) {
@@ -3515,7 +3931,7 @@ int net_if_down(struct net_if *iface)
 	/* Notify L2 to disable the interface */
 	status = net_if_l2(iface)->enable(iface, false);
 	if (status < 0) {
-		return status;
+		goto out;
 	}
 
 done:
@@ -3523,7 +3939,10 @@ done:
 
 	net_mgmt_event_notify(NET_EVENT_IF_DOWN, iface);
 
-	return 0;
+out:
+	k_mutex_unlock(&lock);
+
+	return status;
 }
 
 static int promisc_mode_set(struct net_if *iface, bool enable)
@@ -3546,6 +3965,8 @@ static int promisc_mode_set(struct net_if *iface, bool enable)
 		}
 	}
 #else
+	ARG_UNUSED(enable);
+
 	return -ENOTSUP;
 #endif
 
@@ -3556,29 +3977,40 @@ int net_if_set_promisc(struct net_if *iface)
 {
 	int ret;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	ret = promisc_mode_set(iface, true);
 	if (ret < 0) {
-		return ret;
+		goto out;
 	}
 
 	ret = net_if_flag_test_and_set(iface, NET_IF_PROMISC);
 	if (ret) {
-		return -EALREADY;
+		ret = -EALREADY;
+		goto out;
 	}
 
-	return 0;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 void net_if_unset_promisc(struct net_if *iface)
 {
 	int ret;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	ret = promisc_mode_set(iface, false);
 	if (ret < 0) {
-		return;
+		goto out;
 	}
 
 	net_if_flag_clear(iface, NET_IF_PROMISC);
+
+out:
+	k_mutex_unlock(&lock);
 }
 
 bool net_if_is_promisc(struct net_if *iface)
@@ -3592,30 +4024,47 @@ bool net_if_is_promisc(struct net_if *iface)
 
 int net_if_suspend(struct net_if *iface)
 {
+	int ret = 0;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (net_if_are_pending_tx_packets(iface)) {
-		return -EBUSY;
+		ret = -EBUSY;
+		goto out;
 	}
 
 	if (net_if_flag_test_and_set(iface, NET_IF_SUSPENDED)) {
-		return -EALREADY;
+		ret = -EALREADY;
+		goto out;
 	}
 
 	net_stats_add_suspend_start_time(iface, k_cycle_get_32());
 
-	return 0;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 int net_if_resume(struct net_if *iface)
 {
+	int ret = 0;
+
+	k_mutex_lock(&lock, K_FOREVER);
+
 	if (!net_if_flag_is_set(iface, NET_IF_SUSPENDED)) {
-		return -EALREADY;
+		ret = -EALREADY;
+		goto out;
 	}
 
 	net_if_flag_clear(iface, NET_IF_SUSPENDED);
 
 	net_stats_add_suspend_end_time(iface, k_cycle_get_32());
 
-	return 0;
+out:
+	k_mutex_unlock(&lock);
+
+	return ret;
 }
 
 bool net_if_is_suspended(struct net_if *iface)
@@ -3645,23 +4094,33 @@ void net_if_register_timestamp_cb(struct net_if_timestamp_cb *handle,
 				  struct net_if *iface,
 				  net_if_timestamp_callback_t cb)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	sys_slist_find_and_remove(&timestamp_callbacks, &handle->node);
 	sys_slist_prepend(&timestamp_callbacks, &handle->node);
 
 	handle->iface = iface;
 	handle->cb = cb;
 	handle->pkt = pkt;
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_unregister_timestamp_cb(struct net_if_timestamp_cb *handle)
 {
+	k_mutex_lock(&lock, K_FOREVER);
+
 	sys_slist_find_and_remove(&timestamp_callbacks, &handle->node);
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_call_timestamp_cb(struct net_pkt *pkt)
 {
 	sys_snode_t *sn, *sns;
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	SYS_SLIST_FOR_EACH_NODE_SAFE(&timestamp_callbacks, sn, sns) {
 		struct net_if_timestamp_cb *handle =
 			CONTAINER_OF(sn, struct net_if_timestamp_cb, node);
@@ -3672,6 +4131,8 @@ void net_if_call_timestamp_cb(struct net_pkt *pkt)
 			handle->cb(pkt);
 		}
 	}
+
+	k_mutex_unlock(&lock);
 }
 
 void net_if_add_tx_timestamp(struct net_pkt *pkt)
@@ -3686,6 +4147,8 @@ void net_if_init(void)
 
 	NET_DBG("");
 
+	k_mutex_lock(&lock, K_FOREVER);
+
 	net_tc_tx_init();
 
 	Z_STRUCT_SECTION_FOREACH(net_if, iface) {
@@ -3695,7 +4158,7 @@ void net_if_init(void)
 
 	if (if_count == 0) {
 		NET_ERR("There is no network interface to work with!");
-		return;
+		goto out;
 	}
 
 	iface_ipv6_init(if_count);
@@ -3728,6 +4191,9 @@ void net_if_init(void)
 			 CONFIG_NET_VLAN_COUNT, if_count);
 	}
 #endif
+
+out:
+	k_mutex_unlock(&lock);
 }
 
 void net_if_post_init(void)
diff --git a/subsys/net/lib/lwm2m/CMakeLists.txt b/subsys/net/lib/lwm2m/CMakeLists.txt
index 827ddfb739bbb89de9aa48a823653ef930a1a333..d11d0347027a948ee94fc1c538b4824953c5356f 100644
--- a/subsys/net/lib/lwm2m/CMakeLists.txt
+++ b/subsys/net/lib/lwm2m/CMakeLists.txt
@@ -9,6 +9,7 @@ zephyr_library_sources(
     lwm2m_obj_security.c
     lwm2m_obj_server.c
     lwm2m_obj_device.c
+    lwm2m_rw_link_format.c
     lwm2m_rw_plain_text.c
     lwm2m_rw_oma_tlv.c
     lwm2m_util.c
diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c
index a56e2ddaf24247177fa4f2f9a96cfbeba15f471a..a75088f33d2eb2c3f08cebfcb4540b3a4381f9e9 100644
--- a/subsys/net/lib/lwm2m/lwm2m_engine.c
+++ b/subsys/net/lib/lwm2m/lwm2m_engine.c
@@ -40,6 +40,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
 
 #include "lwm2m_object.h"
 #include "lwm2m_engine.h"
+#include "lwm2m_rw_link_format.h"
 #include "lwm2m_rw_plain_text.h"
 #include "lwm2m_rw_oma_tlv.h"
 #ifdef CONFIG_LWM2M_RW_JSON_SUPPORT
@@ -59,28 +60,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
 #define ENGINE_UPDATE_INTERVAL_MS 500
 #define OBSERVE_COUNTER_START 0U
 
-#define WELL_KNOWN_CORE_PATH	"</.well-known/core>"
-
-/*
- * TODO: to implement a way for clients to specify alternate path
- * via Kconfig (LwM2M specification 8.2.2 Alternate Path)
- *
- * For now, in order to inform server we support JSON format, we have to
- * report 'ct=11543' to the server. '</>' is required in order to append
- * content attribute. And resource type attribute is appended because of
- * Eclipse wakaama will reject the registration when 'rt="oma.lwm2m"' is
- * missing.
- */
-
-#define RESOURCE_TYPE		";rt=\"oma.lwm2m\""
-
-#if defined(CONFIG_LWM2M_RW_JSON_SUPPORT)
-#define REG_PREFACE		"</>" RESOURCE_TYPE \
-				";ct=" STRINGIFY(LWM2M_FORMAT_OMA_JSON)
-#else
-#define REG_PREFACE		""
-#endif
-
 #if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN)
 #define	COAP_OPTION_BUF_LEN	(CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE + 1)
 #else
@@ -1101,17 +1080,13 @@ void lwm2m_acknowledge(struct lwm2m_ctx *client_ctx)
 	request->acknowledged = true;
 }
 
-uint16_t lwm2m_get_rd_data(uint8_t *client_data, uint16_t size)
+int lwm2m_register_payload_handler(struct lwm2m_message *msg)
 {
 	struct lwm2m_engine_obj *obj;
 	struct lwm2m_engine_obj_inst *obj_inst;
-	uint8_t temp[32];
-	uint16_t pos = 0U;
-	int len;
+	int ret;
 
-	/* Add resource-type/content-type to the registration message */
-	memcpy(client_data, REG_PREFACE, sizeof(REG_PREFACE) - 1);
-	pos += sizeof(REG_PREFACE) - 1;
+	engine_put_begin(&msg->out, NULL);
 
 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
 		/* Security obj MUST NOT be part of registration message */
@@ -1121,43 +1096,37 @@ uint16_t lwm2m_get_rd_data(uint8_t *client_data, uint16_t size)
 
 		/* Only report <OBJ_ID> when no instance available */
 		if (obj->instance_count == 0U) {
-			len = snprintk(temp, sizeof(temp), "%s</%u>",
-				       (pos > 0) ? "," : "", obj->obj_id);
-			if (pos + len >= size) {
-				/* full buffer -- exit loop */
-				break;
+			struct lwm2m_obj_path path = {
+				.obj_id = obj->obj_id,
+				.level = LWM2M_PATH_LEVEL_OBJECT,
+			};
+
+			ret = engine_put_corelink(&msg->out, &path);
+			if (ret < 0) {
+				return ret;
 			}
 
-			memcpy(&client_data[pos], temp, len);
-			pos += len;
 			continue;
 		}
 
 		SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list,
 					     obj_inst, node) {
 			if (obj_inst->obj->obj_id == obj->obj_id) {
-				len = snprintk(temp, sizeof(temp),
-					       "%s</%u/%u>",
-					       (pos > 0) ? "," : "",
-					       obj_inst->obj->obj_id,
-					       obj_inst->obj_inst_id);
-				/*
-				 * TODO: iterate through resources once block
-				 * transfer is handled correctly
-				 */
-				if (pos + len >= size) {
-					/* full buffer -- exit loop */
-					break;
-				}
+				struct lwm2m_obj_path path = {
+					.obj_id = obj_inst->obj->obj_id,
+					.obj_inst_id = obj_inst->obj_inst_id,
+					.level = LWM2M_PATH_LEVEL_OBJECT_INST,
+				};
 
-				memcpy(&client_data[pos], temp, len);
-				pos += len;
+				ret = engine_put_corelink(&msg->out, &path);
+				if (ret < 0) {
+					return ret;
+				}
 			}
 		}
 	}
 
-	client_data[pos] = '\0';
-	return pos;
+	return 0;
 }
 
 /* input / output selection */
@@ -1167,7 +1136,7 @@ static int select_writer(struct lwm2m_output_context *out, uint16_t accept)
 	switch (accept) {
 
 	case LWM2M_FORMAT_APP_LINK_FORMAT:
-		/* TODO: rewrite do_discover as content formatter */
+		out->writer = &link_format_writer;
 		break;
 
 	case LWM2M_FORMAT_PLAIN_TEXT:
@@ -1367,6 +1336,37 @@ static int path_to_objs(const struct lwm2m_obj_path *path,
 	return 0;
 }
 
+struct lwm2m_attr *lwm2m_engine_get_next_attr(const void *ref,
+					      struct lwm2m_attr *prev)
+{
+	struct lwm2m_attr *iter = (prev == NULL) ? write_attr_pool : prev + 1;
+	struct lwm2m_attr *result = NULL;
+
+	if (!PART_OF_ARRAY(write_attr_pool, iter)) {
+		return NULL;
+	}
+
+	while (iter < &write_attr_pool[ARRAY_SIZE(write_attr_pool)]) {
+		if (ref == iter->ref) {
+			result = iter;
+			break;
+		}
+
+		++iter;
+	}
+
+	return result;
+}
+
+const char *lwm2m_engine_get_attr_name(const struct lwm2m_attr *attr)
+{
+	if (attr->type >= NR_LWM2M_ATTR) {
+		return NULL;
+	}
+
+	return LWM2M_ATTR_STR[attr->type];
+}
+
 int lwm2m_engine_create_obj_inst(char *pathstr)
 {
 	struct lwm2m_obj_path path;
@@ -3217,91 +3217,25 @@ move_forward:
 	return ret;
 }
 
-static int print_attr(struct lwm2m_output_context *out,
-		      uint8_t *buf, uint16_t buflen, void *ref)
+int lwm2m_discover_handler(struct lwm2m_message *msg, bool is_bootstrap)
 {
-	struct lwm2m_attr *attr;
-	int i, used, base, ret;
-	uint8_t digit;
-	int32_t fraction;
-
-	for (i = 0; i < CONFIG_LWM2M_NUM_ATTR; i++) {
-		if (ref != write_attr_pool[i].ref) {
-			continue;
-		}
-
-		attr = write_attr_pool + i;
-
-		/* assuming integer will have float_val.val2 set as 0 */
-
-		used = snprintk(buf, buflen, ";%s=%s%d%s",
-				LWM2M_ATTR_STR[attr->type],
-				attr->float_val.val1 == 0 &&
-				attr->float_val.val2 < 0 ? "-" : "",
-				attr->float_val.val1,
-				attr->float_val.val2 != 0 ? "." : "");
-
-		base = 100000;
-		fraction = attr->float_val.val2 < 0 ?
-			   -attr->float_val.val2 : attr->float_val.val2;
-		while (fraction && used < buflen && base > 0) {
-			digit = fraction / base;
-			buf[used++] = '0' + digit;
-			fraction -= digit * base;
-			base /= 10;
-		}
-
-		ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf, used);
-		if (ret < 0) {
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int print_resource_dimension(struct lwm2m_output_context *out,
-				    uint8_t *buf, uint16_t buflen,
-				    struct lwm2m_engine_res *res)
-{
-	int ret, i, inst_count = 0;
-
-	if (res->multi_res_inst) {
-		for (i = 0; i < res->res_inst_count; i++) {
-			if (res->res_instances[i].res_inst_id !=
-			    RES_INSTANCE_NOT_CREATED) {
-				inst_count++;
-			}
-		}
-
-		snprintk(buf, buflen, ";dim=%d", inst_count);
-		ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf,
-				 strlen(buf));
-		if (ret < 0) {
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int do_discover_op(struct lwm2m_message *msg, bool well_known)
-{
-	static char disc_buf[24];
 	struct lwm2m_engine_obj *obj;
 	struct lwm2m_engine_obj_inst *obj_inst;
 	int ret;
 	bool reported = false;
 
-	/* object ID is required unless it's a ".well-known/core" discovery
-	 * ref: lwm2m spec 20170208-A table 11
-	 */
-	if (!well_known &&
-	    (msg->path.level == 0U ||
+	/* Object ID is required in Device Management Discovery (5.4.2). */
+	if (!is_bootstrap &&
+	    (msg->path.level == LWM2M_PATH_LEVEL_NONE ||
 	     msg->path.obj_id == LWM2M_OBJECT_SECURITY_ID)) {
 		return -EPERM;
 	}
 
+	/* Bootstrap discovery allows to specify at most Object ID. */
+	if (is_bootstrap && msg->path.level > LWM2M_PATH_LEVEL_OBJECT) {
+		return -EPERM;
+	}
+
 	/* set output content-format */
 	ret = coap_append_option_int(msg->out.out_cpkt,
 				     COAP_OPTION_CONTENT_FORMAT,
@@ -3316,141 +3250,117 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known)
 		return ret;
 	}
 
-	/* Handle CoAP .well-known/core discover */
-	if (well_known) {
-		/* </.well-known/core> */
-		ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-				 WELL_KNOWN_CORE_PATH,
-				 strlen(WELL_KNOWN_CORE_PATH));
-		if (ret < 0) {
-			return ret;
-		}
-
-		SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
-			snprintk(disc_buf, sizeof(disc_buf), ",</%u>",
-				 obj->obj_id);
-
-			ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-					 disc_buf, strlen(disc_buf));
-			if (ret < 0) {
-				return ret;
-			}
-		}
-
-		return 0;
-	}
-
-	/* Report object attributes only when Object ID (alone) was
-	 * provided (and do it only once in case of multiple instances).
+	/*
+	 * Add required prefix for bootstrap discovery (5.2.7.3).
+	 * For device management discovery, `engine_put_begin()` adds nothing.
 	 */
-	if (msg->path.level == 1) {
-		SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
-			if (obj->obj_id != msg->path.obj_id) {
-				continue;
-			}
-
-			snprintk(disc_buf, sizeof(disc_buf), "%s</%u>",
-				 reported ? "," : "", obj->obj_id);
+	engine_put_begin(&msg->out, &msg->path);
 
-			ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-					 disc_buf, strlen(disc_buf));
-			if (ret < 0) {
-				return ret;
-			}
+	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
+		/* Skip unrelated objects */
+		if (msg->path.level > 0 && msg->path.obj_id != obj->obj_id) {
+			continue;
+		}
 
-			/* report object attrs (5.4.2) */
-			ret = print_attr(&msg->out, disc_buf, sizeof(disc_buf),
-					 obj);
+		/* For bootstrap discover, only report object ID when no
+		 * instance is available.
+		 * For device management discovery, only report object ID with
+		 * attributes if object ID (alone) was provided.
+		 */
+		if ((is_bootstrap && obj->instance_count == 0U) ||
+		    (!is_bootstrap && msg->path.level == LWM2M_PATH_LEVEL_OBJECT)) {
+			struct lwm2m_obj_path path = {
+				.obj_id = obj->obj_id,
+				.level = LWM2M_PATH_LEVEL_OBJECT,
+			};
+
+			ret = engine_put_corelink(&msg->out, &path);
 			if (ret < 0) {
 				return ret;
 			}
 
 			reported = true;
-			break;
-		}
-	}
 
-	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
-		if (obj_inst->obj->obj_id != msg->path.obj_id) {
-			continue;
-		}
-
-		/* skip unrelated object instance */
-		if (msg->path.level > 1 &&
-		    msg->path.obj_inst_id != obj_inst->obj_inst_id) {
-			continue;
+			if (is_bootstrap) {
+				continue;
+			}
 		}
 
-		/* Report object instances only if Resource ID is missing. */
-		if (msg->path.level <= 2U) {
-			snprintk(disc_buf, sizeof(disc_buf), "%s</%u/%u>",
-				 reported ? "," : "",
-				 obj_inst->obj->obj_id, obj_inst->obj_inst_id);
+		SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list,
+					     obj_inst, node) {
+			if (obj_inst->obj->obj_id != obj->obj_id) {
+				continue;
+			}
 
-			ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-					 disc_buf, strlen(disc_buf));
-			if (ret < 0) {
-				return ret;
+			/* Skip unrelated object instance. */
+			if (msg->path.level > LWM2M_PATH_LEVEL_OBJECT &&
+			    msg->path.obj_inst_id != obj_inst->obj_inst_id) {
+				continue;
 			}
 
-			/* Report object instance attributes only when Instance
-			 * ID was specified (5.4.2).
+			/* Report object instances only if no Resource ID is
+			 * provided.
 			 */
-			if (msg->path.level == 2U) {
-				ret = print_attr(&msg->out, disc_buf,
-						 sizeof(disc_buf), obj_inst);
+			if (msg->path.level <= LWM2M_PATH_LEVEL_OBJECT_INST) {
+				struct lwm2m_obj_path path = {
+					.obj_id = obj_inst->obj->obj_id,
+					.obj_inst_id = obj_inst->obj_inst_id,
+					.level = LWM2M_PATH_LEVEL_OBJECT_INST,
+				};
+
+				ret = engine_put_corelink(&msg->out, &path);
 				if (ret < 0) {
 					return ret;
 				}
-			}
 
-			reported = true;
-		}
+				reported = true;
+			}
 
-		for (int i = 0; i < obj_inst->resource_count; i++) {
-			/* skip unrelated resources */
-			if (msg->path.level == 3U &&
-			    msg->path.res_id != obj_inst->resources[i].res_id) {
+			/* Do not report resources in bootstrap discovery. */
+			if (is_bootstrap) {
 				continue;
 			}
 
-			snprintk(disc_buf, sizeof(disc_buf),
-				 "%s</%u/%u/%u>",
-				 reported ? "," : "",
-				 obj_inst->obj->obj_id,
-				 obj_inst->obj_inst_id,
-				 obj_inst->resources[i].res_id);
+			for (int i = 0; i < obj_inst->resource_count; i++) {
+				/* Skip unrelated resources. */
+				if (msg->path.level == LWM2M_PATH_LEVEL_RESOURCE &&
+				    msg->path.res_id != obj_inst->resources[i].res_id) {
+					continue;
+				}
 
-			ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-					 disc_buf, strlen(disc_buf));
-			if (ret < 0) {
-				return ret;
-			}
+				struct lwm2m_obj_path path = {
+					.obj_id = obj_inst->obj->obj_id,
+					.obj_inst_id = obj_inst->obj_inst_id,
+					.res_id = obj_inst->resources[i].res_id,
+					.level = LWM2M_PATH_LEVEL_RESOURCE,
+				};
 
-			/* report resource attrs when path > 1 (5.4.2) */
-			if (msg->path.level > 1) {
-				ret = print_resource_dimension(
-					&msg->out, disc_buf, sizeof(disc_buf),
-					&obj_inst->resources[i]);
+				ret = engine_put_corelink(&msg->out, &path);
 				if (ret < 0) {
 					return ret;
 				}
 
-				ret = print_attr(&msg->out,
-						 disc_buf, sizeof(disc_buf),
-						 &obj_inst->resources[i]);
-				if (ret < 0) {
-					return ret;
-				}
+				reported = true;
 			}
-
-			reported = true;
 		}
 	}
 
 	return reported ? 0 : -ENOENT;
 }
 
+static int do_discover_op(struct lwm2m_message *msg, uint16_t content_format)
+{
+	switch (content_format) {
+	case LWM2M_FORMAT_APP_LINK_FORMAT:
+		return do_discover_op_link_format(
+				msg, msg->ctx->bootstrap_mode);
+
+	default:
+		LOG_ERR("Unsupported format: %u", content_format);
+		return -ENOMSG;
+	}
+}
+
 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
 				   struct lwm2m_engine_obj_inst **obj_inst,
 				   uint8_t *created)
@@ -3486,6 +3396,44 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
 	return ret;
 }
 
+struct lwm2m_engine_obj *lwm2m_engine_get_obj(
+					const struct lwm2m_obj_path *path)
+{
+	if (path->level < LWM2M_PATH_LEVEL_OBJECT) {
+		return NULL;
+	}
+
+	return get_engine_obj(path->obj_id);
+}
+
+struct lwm2m_engine_obj_inst *lwm2m_engine_get_obj_inst(
+					const struct lwm2m_obj_path *path)
+{
+	if (path->level < LWM2M_PATH_LEVEL_OBJECT_INST) {
+		return NULL;
+	}
+
+	return get_engine_obj_inst(path->obj_id, path->obj_inst_id);
+}
+
+struct lwm2m_engine_res *lwm2m_engine_get_res(
+					const struct lwm2m_obj_path *path)
+{
+	struct lwm2m_engine_res *res = NULL;
+	int ret;
+
+	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
+		return NULL;
+	}
+
+	ret = path_to_objs(path, NULL, NULL, &res, NULL);
+	if (ret < 0) {
+		return NULL;
+	}
+
+	return res;
+}
+
 static int do_write_op(struct lwm2m_message *msg,
 		       uint16_t format)
 {
@@ -3587,149 +3535,6 @@ static int bootstrap_delete(struct lwm2m_message *msg)
 
 	return ret;
 }
-
-static inline int bs_discover_fill_enabler(struct lwm2m_message *msg)
-{
-	char buf[sizeof("lwm2m='" LWM2M_PROTOCOL_VERSION "'")];
-
-	snprintk(buf, sizeof(buf), "lwm2m=\"%s\"", LWM2M_PROTOCOL_VERSION);
-	return buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), buf, strlen(buf));
-}
-
-static inline int bs_discover_fill_object(struct lwm2m_engine_obj *obj,
-					  struct lwm2m_message *msg)
-{
-	char buf[sizeof(",</xxxxx>")];
-
-	snprintk(buf, sizeof(buf), ",</%u>", obj->obj_id);
-	return buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), buf, strlen(buf));
-}
-
-static int bs_discover_fill_instance(struct lwm2m_engine_obj_inst *obj_inst,
-				     struct lwm2m_message *msg)
-{
-	char buf[sizeof(",</xxxxx/xxxxx>")];
-	bool bootstrap_inst;
-	uint16_t server_id;
-	int ret;
-
-	snprintk(buf, sizeof(buf), ",</%u/%u>", obj_inst->obj->obj_id,
-		 obj_inst->obj_inst_id);
-
-	ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), buf, strlen(buf));
-	if (ret < 0) {
-		return ret;
-	}
-
-	/* Security and Server instnaces shall report Short Server ID associated
-	 * with them (but only if not bootstrap instance).
-	 */
-	if (obj_inst->obj->obj_id == LWM2M_OBJECT_SECURITY_ID) {
-		snprintk(buf, sizeof(buf), "0/%d/1", obj_inst->obj_inst_id);
-		ret = lwm2m_engine_get_bool(buf, &bootstrap_inst);
-		if (ret < 0) {
-			return ret;
-		}
-
-		if (!bootstrap_inst) {
-			snprintk(buf, sizeof(buf), "0/%d/10",
-				 obj_inst->obj_inst_id);
-			ret = lwm2m_engine_get_u16(buf, &server_id);
-			if (ret < 0) {
-				return ret;
-			}
-
-			snprintk(buf, sizeof(buf), ";ssid=%d", server_id);
-			ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-					buf, strlen(buf));
-			if (ret < 0) {
-				return ret;
-			}
-		}
-	}
-
-	if (obj_inst->obj->obj_id == LWM2M_OBJECT_SERVER_ID) {
-		snprintk(buf, sizeof(buf), "1/%d/0", obj_inst->obj_inst_id);
-		ret = lwm2m_engine_get_u16(buf, &server_id);
-		if (ret < 0) {
-			return ret;
-		}
-
-		snprintk(buf, sizeof(buf), ";ssid=%d", server_id);
-		ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt),
-				 buf, strlen(buf));
-		if (ret < 0) {
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int bootstrap_discover(struct lwm2m_message *msg)
-{
-	struct lwm2m_engine_obj *obj;
-	struct lwm2m_engine_obj_inst *obj_inst;
-	int ret;
-	bool reported = false;
-
-	/* set output content-format */
-	ret = coap_append_option_int(msg->out.out_cpkt,
-				     COAP_OPTION_CONTENT_FORMAT,
-				     LWM2M_FORMAT_APP_LINK_FORMAT);
-	if (ret < 0) {
-		LOG_ERR("Error setting response content-format: %d", ret);
-		return ret;
-	}
-
-	ret = coap_packet_append_payload_marker(msg->out.out_cpkt);
-	if (ret < 0) {
-		return ret;
-	}
-
-	/*
-	 * lwm2m spec 20170208-A sec 5.2.7.3 bootstrap discover on "/"
-	 * - prefixed w/ lwm2m enabler version. e.g. lwm2m="1.0"
-	 * - returns object and object instances only
-	 */
-	ret = bs_discover_fill_enabler(msg);
-	if (ret < 0) {
-		return ret;
-	}
-
-	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
-		if (msg->path.level > 0 && msg->path.obj_id != obj->obj_id) {
-			continue;
-		}
-
-		/* Only report </OBJ_ID> when no instance available */
-		if (obj->instance_count == 0U) {
-			ret = bs_discover_fill_object(obj, msg);
-			if (ret < 0) {
-				return ret;
-			}
-
-			reported = true;
-			continue;
-		}
-
-		SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list,
-					     obj_inst, node) {
-			if (obj_inst->obj->obj_id != obj->obj_id) {
-				continue;
-			}
-
-			ret = bs_discover_fill_instance(obj_inst, msg);
-			if (ret < 0) {
-				return ret;
-			}
-
-			reported = true;
-		}
-	}
-
-	return reported ? 0 : -ENOENT;
-}
 #endif
 
 static int handle_request(struct coap_packet *request,
@@ -3743,7 +3548,6 @@ static int handle_request(struct coap_packet *request,
 	uint8_t tkl = 0U;
 	uint16_t format = LWM2M_FORMAT_NONE, accept;
 	int observe = -1; /* default to -1, 0 = ENABLE, 1 = DISABLE */
-	bool well_known = false;
 	int block_opt, block_num;
 	struct lwm2m_block_context *block_ctx = NULL;
 	enum coap_block_size block_size;
@@ -3803,22 +3607,10 @@ static int handle_request(struct coap_packet *request,
 		}
 	}
 
-	/* check for .well-known/core URI query (DISCOVER) */
-	if (r == 2 &&
-	    (options[0].len == 11U &&
-	     strncmp(options[0].value, ".well-known", 11) == 0) &&
-	    (options[1].len == 4U &&
-	     strncmp(options[1].value, "core", 4) == 0)) {
-		if ((code & COAP_REQUEST_MASK) != COAP_METHOD_GET) {
-			r = -EPERM;
-			goto error;
-		}
-
-		well_known = true;
 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
 	/* check for bootstrap-finish */
-	} else if ((code & COAP_REQUEST_MASK) == COAP_METHOD_POST && r == 1 && \
-		   strncmp(options[0].value, "bs", options[0].len) == 0) {
+	if ((code & COAP_REQUEST_MASK) == COAP_METHOD_POST && r == 1 &&
+	    strncmp(options[0].value, "bs", options[0].len) == 0) {
 		engine_bootstrap_finish();
 
 		msg->code = COAP_RESPONSE_CODE_CHANGED;
@@ -3829,8 +3621,9 @@ static int handle_request(struct coap_packet *request,
 		}
 
 		return 0;
+	} else
 #endif
-	} else {
+	{
 		r = coap_options_to_path(options, r, &msg->path);
 		if (r < 0) {
 			r = -ENOENT;
@@ -3863,8 +3656,7 @@ static int handle_request(struct coap_packet *request,
 		goto error;
 	}
 
-	if (!well_known && !(msg->ctx->bootstrap_mode &&
-			     msg->path.level == 0)) {
+	if (!(msg->ctx->bootstrap_mode && msg->path.level == 0)) {
 		/* find registered obj */
 		obj = get_engine_obj(msg->path.obj_id);
 		if (!obj) {
@@ -3882,7 +3674,7 @@ static int handle_request(struct coap_packet *request,
 		 * LwM2M V1_0_1-20170704-A, table 25,
 		 * Discover: CoAP GET + accept=LWM2M_FORMAT_APP_LINK_FORMAT
 		 */
-		if (well_known || accept == LWM2M_FORMAT_APP_LINK_FORMAT) {
+		if (accept == LWM2M_FORMAT_APP_LINK_FORMAT) {
 			msg->operation = LWM2M_OP_DISCOVER;
 			accept = LWM2M_FORMAT_APP_LINK_FORMAT;
 		} else {
@@ -4046,13 +3838,7 @@ static int handle_request(struct coap_packet *request,
 			break;
 
 		case LWM2M_OP_DISCOVER:
-#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
-			if (msg->ctx->bootstrap_mode) {
-				r = bootstrap_discover(msg);
-				break;
-			}
-#endif
-			r = do_discover_op(msg, well_known);
+			r = do_discover_op(msg, accept);
 			break;
 
 		case LWM2M_OP_WRITE:
diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h
index db7fac79b29fe48f2db08b05eaa9d768b4437c28..46ab089f8135143537492ac8bb4dd940faa0db0a 100644
--- a/subsys/net/lib/lwm2m/lwm2m_engine.h
+++ b/subsys/net/lib/lwm2m/lwm2m_engine.h
@@ -65,6 +65,13 @@ int  lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
 				    struct lwm2m_engine_obj_inst **obj_inst,
 				    uint8_t *created);
 
+struct lwm2m_engine_obj *lwm2m_engine_get_obj(
+					const struct lwm2m_obj_path *path);
+struct lwm2m_engine_obj_inst *lwm2m_engine_get_obj_inst(
+					const struct lwm2m_obj_path *path);
+struct lwm2m_engine_res *lwm2m_engine_get_res(
+					const struct lwm2m_obj_path *path);
+
 /* LwM2M context functions */
 int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx);
 void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx);
@@ -80,7 +87,7 @@ int lwm2m_init_message(struct lwm2m_message *msg);
 int lwm2m_send_message(struct lwm2m_message *msg);
 int lwm2m_send_empty_ack(struct lwm2m_ctx *client_ctx, uint16_t mid);
 
-uint16_t lwm2m_get_rd_data(uint8_t *client_data, uint16_t size);
+int lwm2m_register_payload_handler(struct lwm2m_message *msg);
 
 int lwm2m_perform_read_op(struct lwm2m_message *msg, uint16_t content_format);
 
@@ -90,6 +97,8 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst,
 			struct lwm2m_engine_obj_field *obj_field,
 			struct lwm2m_message *msg);
 
+int lwm2m_discover_handler(struct lwm2m_message *msg, bool is_bootstrap);
+
 enum coap_block_size lwm2m_default_block_size(void);
 
 int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms);
@@ -118,6 +127,12 @@ void lwm2m_firmware_set_update_result(uint8_t result);
 uint8_t lwm2m_firmware_get_update_result(void);
 #endif
 
+/* Attribute handling. */
+
+struct lwm2m_attr *lwm2m_engine_get_next_attr(const void *ref,
+					      struct lwm2m_attr *prev);
+const char *lwm2m_engine_get_attr_name(const struct lwm2m_attr *attr);
+
 /* Network Layer */
 int  lwm2m_socket_add(struct lwm2m_ctx *ctx);
 void lwm2m_socket_del(struct lwm2m_ctx *ctx);
diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h
index 433a77555a32ca48cbb64d136c80ab1fe378294d..d4a9a93a5f00aeff68ebf5eb7c3c962c30cb8dc1 100644
--- a/subsys/net/lib/lwm2m/lwm2m_object.h
+++ b/subsys/net/lib/lwm2m/lwm2m_object.h
@@ -52,6 +52,7 @@
 #include <net/net_ip.h>
 #include <sys/printk.h>
 #include <sys/util.h>
+#include <sys/types.h>
 
 #include <net/coap.h>
 #include <net/lwm2m.h>
@@ -140,6 +141,12 @@
 struct lwm2m_engine_obj;
 struct lwm2m_message;
 
+#define LWM2M_PATH_LEVEL_NONE 0
+#define LWM2M_PATH_LEVEL_OBJECT 1
+#define LWM2M_PATH_LEVEL_OBJECT_INST 2
+#define LWM2M_PATH_LEVEL_RESOURCE 3
+#define LWM2M_PATH_LEVEL_RESOURCE_INST 4
+
 /* path representing object instances */
 struct lwm2m_obj_path {
 	uint16_t obj_id;
@@ -516,6 +523,8 @@ struct lwm2m_writer {
 	size_t (*put_objlnk)(struct lwm2m_output_context *out,
 			     struct lwm2m_obj_path *path,
 			     struct lwm2m_objlnk *value);
+	ssize_t (*put_corelink)(struct lwm2m_output_context *out,
+				const struct lwm2m_obj_path *path);
 };
 
 struct lwm2m_reader {
@@ -731,6 +740,16 @@ static inline size_t engine_put_objlnk(struct lwm2m_output_context *out,
 	return out->writer->put_objlnk(out, path, value);
 }
 
+static inline ssize_t engine_put_corelink(struct lwm2m_output_context *out,
+					  const struct lwm2m_obj_path *path)
+{
+	if (out->writer->put_corelink) {
+		return out->writer->put_corelink(out, path);
+	}
+
+	return -ENOTSUP;
+}
+
 static inline size_t engine_get_s32(struct lwm2m_input_context *in,
 				    int32_t *value)
 {
diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c
index b67b156b443114879af266fbf874e311bf8d4b13..2f11a5626c9ddcba7def7eefb59a48cc288a8c25 100644
--- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c
+++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c
@@ -58,6 +58,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
 
 #include "lwm2m_object.h"
 #include "lwm2m_engine.h"
+#include "lwm2m_rw_link_format.h"
 
 #define LWM2M_RD_CLIENT_URI "rd"
 
@@ -122,7 +123,6 @@ struct lwm2m_rd_client_info {
  * documented in the LwM2M specification.
  */
 static char query_buffer[MAX(32, sizeof("ep=") + CLIENT_EP_LEN)];
-static uint8_t client_data[256]; /* allocate some data for the RD */
 
 void engine_update_tx_time(void)
 {
@@ -663,7 +663,6 @@ static int sm_send_registration(bool send_obj_support_data,
 				lwm2m_message_timeout_cb_t timeout_cb)
 {
 	struct lwm2m_message *msg;
-	uint16_t client_data_len;
 	int ret;
 	char binding[CLIENT_BINDING_LEN];
 
@@ -766,11 +765,10 @@ static int sm_send_registration(bool send_obj_support_data,
 			goto cleanup;
 		}
 
-		/* generate the rd data */
-		client_data_len = lwm2m_get_rd_data(client_data,
-						    sizeof(client_data));
-		ret = buf_append(CPKT_BUF_WRITE(&msg->cpkt), client_data,
-				 client_data_len);
+		msg->out.out_cpkt = &msg->cpkt;
+		msg->out.writer = &link_format_writer;
+
+		ret = do_register_op_link_format(msg);
 		if (ret < 0) {
 			goto cleanup;
 		}
diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_link_format.c b/subsys/net/lib/lwm2m/lwm2m_rw_link_format.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0b67c527a7b27d6cbdec6d94a82356ef1b082c4
--- /dev/null
+++ b/subsys/net/lib/lwm2m/lwm2m_rw_link_format.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdint.h>
+#include <logging/log.h>
+
+#include "lwm2m_engine.h"
+#include "lwm2m_rw_link_format.h"
+
+LOG_MODULE_REGISTER(net_lwm2m_link_format, CONFIG_LWM2M_LOG_LEVEL);
+
+#define CORELINK_BUF_SIZE 24
+
+#define ENABLER_VERSION "lwm2m=\"" LWM2M_PROTOCOL_VERSION "\""
+
+/*
+ * TODO: to implement a way for clients to specify alternate path
+ * via Kconfig (LwM2M specification 8.2.2 Alternate Path)
+ *
+ * For now, in order to inform server we support JSON format, we have to
+ * report 'ct=11543' to the server. '</>' is required in order to append
+ * content attribute. And resource type attribute is appended because of
+ * Eclipse wakaama will reject the registration when 'rt="oma.lwm2m"' is
+ * missing.
+ */
+
+#if defined(CONFIG_LWM2M_RW_JSON_SUPPORT)
+#define RESOURCE_TYPE		";rt=\"oma.lwm2m\""
+
+#define REG_PREFACE		"</>" RESOURCE_TYPE \
+				";ct=" STRINGIFY(LWM2M_FORMAT_OMA_JSON)
+#else
+#define REG_PREFACE		""
+#endif
+
+enum link_format_mode {
+	LINK_FORMAT_MODE_DISCOVERY,
+	LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY,
+	LINK_FORMAT_MODE_REGISTER,
+};
+
+struct link_format_out_formatter_data {
+	uint8_t request_level;
+	uint8_t mode;
+	bool is_first : 1;
+};
+
+static size_t put_begin(struct lwm2m_output_context *out,
+			struct lwm2m_obj_path *path)
+{
+	char init_string[MAX(sizeof(ENABLER_VERSION), sizeof(REG_PREFACE))];
+	struct link_format_out_formatter_data *fd;
+	int ret;
+
+	ARG_UNUSED(path);
+
+	fd = engine_get_out_user_data(out);
+	if (fd == NULL) {
+		return 0;
+	}
+
+	switch (fd->mode) {
+	case LINK_FORMAT_MODE_DISCOVERY:
+		/* Nothing to add in device management mode. */
+		return 0;
+
+	case LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY:
+		strcpy(init_string, ENABLER_VERSION);
+		break;
+
+	case LINK_FORMAT_MODE_REGISTER:
+		/* Only indicate content type if json is enabled.  */
+		if (!IS_ENABLED(CONFIG_LWM2M_RW_JSON_SUPPORT)) {
+			return 0;
+		}
+
+		strcpy(init_string, REG_PREFACE);
+		break;
+	}
+
+	ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), init_string,
+			 strlen(init_string));
+	if (ret < 0) {
+		return 0;
+	}
+
+	fd->is_first = false;
+
+	return strlen(init_string);
+}
+
+static int put_corelink_separator(struct lwm2m_output_context *out)
+{
+	char comma = ',';
+	int ret;
+
+	ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &comma, sizeof(comma));
+	if (ret < 0) {
+		return ret;
+	}
+
+	return (int)sizeof(comma);
+}
+
+static int put_corelink_dimension(struct lwm2m_output_context *out,
+				  const struct lwm2m_engine_res *res,
+				  uint8_t *buf, uint16_t buflen)
+{
+	int ret, inst_count = 0, len = 0;
+
+	if (res->multi_res_inst) {
+		for (int i = 0; i < res->res_inst_count; i++) {
+			if (res->res_instances[i].res_inst_id !=
+			    RES_INSTANCE_NOT_CREATED) {
+				inst_count++;
+			}
+		}
+
+		len = snprintk(buf, buflen, ";dim=%d", inst_count);
+		if (len < 0 || len >= buflen) {
+			return -ENOMEM;
+		}
+
+		ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf, len);
+		if (ret < 0) {
+			return ret;
+		}
+	}
+
+	return len;
+}
+
+static int put_corelink_attributes(struct lwm2m_output_context *out,
+				   const void *ref, uint8_t *buf,
+				   uint16_t buflen)
+{
+	struct lwm2m_attr *attr = NULL;
+	int used, base, ret;
+	uint8_t digit;
+	int32_t fraction;
+	int len = 0;
+
+	while ((attr = lwm2m_engine_get_next_attr(ref, attr)) != NULL) {
+		const char *name = lwm2m_engine_get_attr_name(attr);
+
+		if (name == NULL) {
+			/* Invalid attribute, ignore. */
+			continue;
+		}
+
+		/* Assuming integer will have float_val.val2 set as 0. */
+		used = snprintk(buf, buflen, ";%s=%s%d%s",
+				name,
+				attr->float_val.val1 == 0 &&
+				attr->float_val.val2 < 0 ? "-" : "",
+				attr->float_val.val1,
+				attr->float_val.val2 != 0 ? "." : "");
+		if (used < 0 || used >= buflen) {
+			return -ENOMEM;
+		}
+
+		base = 100000;
+		fraction = attr->float_val.val2 < 0 ?
+			   -attr->float_val.val2 : attr->float_val.val2;
+		while (fraction && used < buflen && base > 0) {
+			digit = fraction / base;
+			buf[used++] = '0' + digit;
+			fraction -= digit * base;
+			base /= 10;
+		}
+
+		len += used;
+
+		ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf, used);
+		if (ret < 0) {
+			return ret;
+		}
+	}
+
+	return len;
+}
+
+static int put_corelink_ssid(struct lwm2m_output_context *out,
+			     const struct lwm2m_obj_path *path,
+			     uint8_t *buf, uint16_t buflen)
+{
+	uint16_t server_id = 0;
+	int ret;
+	int len;
+
+	switch (path->obj_id) {
+	case LWM2M_OBJECT_SECURITY_ID: {
+		bool bootstrap_inst;
+
+		ret = snprintk(buf, buflen, "0/%d/1",
+			       path->obj_inst_id);
+		if (ret < 0 || ret >= buflen) {
+			return -ENOMEM;
+		}
+
+		ret = lwm2m_engine_get_bool(buf, &bootstrap_inst);
+		if (ret < 0) {
+			return ret;
+		}
+
+		/* Bootstrap Security object instance does not have associated
+		 * Server object instance, so do not report ssid for it.
+		 */
+		if (bootstrap_inst) {
+			return 0;
+		}
+
+		ret = snprintk(buf, buflen, "0/%d/10",
+				path->obj_inst_id);
+		if (ret < 0 || ret >= buflen) {
+			return -ENOMEM;
+		}
+
+		ret = lwm2m_engine_get_u16(buf, &server_id);
+		if (ret < 0) {
+			return ret;
+		}
+
+		break;
+	}
+
+	case LWM2M_OBJECT_SERVER_ID:
+		ret = snprintk(buf, buflen, "1/%d/0", path->obj_inst_id);
+		if (ret < 0 || ret >= buflen) {
+			return -ENOMEM;
+		}
+
+		ret = lwm2m_engine_get_u16(buf, &server_id);
+		if (ret < 0) {
+			return ret;
+		}
+
+		break;
+
+	default:
+		LOG_ERR("Invalid object ID for ssid attribute: %d",
+			path->obj_id);
+		return -EINVAL;
+	}
+
+	len = snprintk(buf, buflen, ";ssid=%d", server_id);
+	if (len < 0 || len >= buflen) {
+		return -ENOMEM;
+	}
+
+	ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf, len);
+	if (ret < 0) {
+		return ret;
+	}
+
+	return len;
+}
+
+static int put_obj_corelink(struct lwm2m_output_context *out,
+			    const struct lwm2m_obj_path *path,
+			    struct link_format_out_formatter_data *fd)
+{
+	char obj_buf[CORELINK_BUF_SIZE];
+	int len = 0;
+	int ret;
+
+	ret = snprintk(obj_buf, sizeof(obj_buf), "</%u>", path->obj_id);
+	if (ret < 0 || ret >= sizeof(obj_buf)) {
+		return -ENOMEM;
+	}
+
+	len += ret;
+
+	ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), obj_buf, len);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (fd->mode == LINK_FORMAT_MODE_DISCOVERY) {
+		/* Report object attributes only in device management mode
+		 * (5.4.2).
+		 */
+		struct lwm2m_engine_obj *obj = lwm2m_engine_get_obj(path);
+
+		if (obj == NULL) {
+			return -EINVAL;
+		}
+
+		ret = put_corelink_attributes(out, obj, obj_buf,
+					      sizeof(obj_buf));
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+	}
+
+	return len;
+}
+
+static int put_obj_inst_corelink(struct lwm2m_output_context *out,
+				 const struct lwm2m_obj_path *path,
+				 struct link_format_out_formatter_data *fd)
+{
+	char obj_buf[CORELINK_BUF_SIZE];
+	int len = 0;
+	int ret;
+
+	ret = snprintk(obj_buf, sizeof(obj_buf), "</%u/%u>",
+		       path->obj_id, path->obj_inst_id);
+	if (ret < 0 || ret >= sizeof(obj_buf)) {
+		return -ENOMEM;
+	}
+
+	len += ret;
+
+	ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), obj_buf, len);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (fd->mode == LINK_FORMAT_MODE_REGISTER) {
+		return len;
+	}
+
+	/* Bootstrap object instance corelink shall only contain ssid
+	 * parameter for Security and Server objects (5.2.7.3).
+	 */
+	if (fd->mode == LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY) {
+		if (path->obj_id == LWM2M_OBJECT_SECURITY_ID ||
+		    path->obj_id == LWM2M_OBJECT_SERVER_ID) {
+			ret = put_corelink_ssid(out, path, obj_buf,
+						sizeof(obj_buf));
+			if (ret < 0) {
+				return ret;
+			}
+
+			len += ret;
+		}
+
+		return len;
+	}
+
+	/* Report object instance attributes only when Instance
+	 * ID was specified (5.4.2).
+	 */
+	if (fd->request_level == LWM2M_PATH_LEVEL_OBJECT_INST) {
+		struct lwm2m_engine_obj_inst *obj_inst =
+					lwm2m_engine_get_obj_inst(path);
+
+		if (obj_inst == NULL) {
+			return -EINVAL;
+		}
+
+		ret = put_corelink_attributes(out, obj_inst, obj_buf,
+					      sizeof(obj_buf));
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+	}
+
+	return len;
+}
+
+static int put_res_corelink(struct lwm2m_output_context *out,
+			    const struct lwm2m_obj_path *path,
+			    struct link_format_out_formatter_data *fd)
+{
+	char obj_buf[CORELINK_BUF_SIZE];
+	int len = 0;
+	int ret;
+
+	if (fd->mode != LINK_FORMAT_MODE_DISCOVERY) {
+		/* Report resources only in device management discovery. */
+		return 0;
+	}
+
+	ret = snprintk(obj_buf, sizeof(obj_buf), "</%u/%u/%u>", path->obj_id,
+		       path->obj_inst_id, path->res_id);
+	if (ret < 0 || ret >= sizeof(obj_buf)) {
+		return -ENOMEM;
+	}
+
+	len += ret;
+
+	ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), obj_buf, len);
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* Report resource attrs when at least object instance was specified
+	 * (5.4.2).
+	 */
+	if (fd->request_level >= LWM2M_PATH_LEVEL_OBJECT_INST) {
+		struct lwm2m_engine_res *res = lwm2m_engine_get_res(path);
+
+		if (res == NULL) {
+			return -EINVAL;
+		}
+
+		ret = put_corelink_dimension(out, res, obj_buf,
+					     sizeof(obj_buf));
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+
+		ret = put_corelink_attributes(out, res, obj_buf,
+					      sizeof(obj_buf));
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+	}
+
+	return len;
+}
+
+static ssize_t put_corelink(struct lwm2m_output_context *out,
+			    const struct lwm2m_obj_path *path)
+{
+	struct link_format_out_formatter_data *fd;
+	ssize_t len = 0;
+	int ret;
+
+	fd = engine_get_out_user_data(out);
+	if (fd == NULL) {
+		return -EINVAL;
+	}
+
+	if (fd->is_first) {
+		fd->is_first = false;
+	} else {
+		ret = put_corelink_separator(out);
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+	}
+
+	switch (path->level) {
+	case LWM2M_PATH_LEVEL_OBJECT:
+		ret =  put_obj_corelink(out, path, fd);
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+		break;
+
+	case LWM2M_PATH_LEVEL_OBJECT_INST:
+		ret = put_obj_inst_corelink(out, path, fd);
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+		break;
+
+	case LWM2M_PATH_LEVEL_RESOURCE:
+		ret = put_res_corelink(out, path, fd);
+		if (ret < 0) {
+			return ret;
+		}
+
+		len += ret;
+		break;
+
+	default:
+		LOG_ERR("Invalid corelink path level: %d", path->level);
+		return -EINVAL;
+	}
+
+	return len;
+}
+
+const struct lwm2m_writer link_format_writer = {
+	.put_begin = put_begin,
+	.put_corelink = put_corelink,
+};
+
+int do_discover_op_link_format(struct lwm2m_message *msg, bool is_bootstrap)
+{
+	struct link_format_out_formatter_data fd;
+	int ret;
+
+	fd.is_first = true;
+	fd.mode = is_bootstrap ? LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY :
+				 LINK_FORMAT_MODE_DISCOVERY;
+	fd.request_level = msg->path.level;
+
+	engine_set_out_user_data(&msg->out, &fd);
+	ret = lwm2m_discover_handler(msg, is_bootstrap);
+	engine_clear_out_user_data(&msg->out);
+
+	return ret;
+}
+
+int do_register_op_link_format(struct lwm2m_message *msg)
+{
+	struct link_format_out_formatter_data fd;
+	int ret;
+
+	fd.is_first = true;
+	fd.mode = LINK_FORMAT_MODE_REGISTER;
+	fd.request_level = LWM2M_PATH_LEVEL_NONE;
+
+	engine_set_out_user_data(&msg->out, &fd);
+	ret = lwm2m_register_payload_handler(msg);
+	engine_clear_out_user_data(&msg->out);
+
+	return ret;
+}
diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_link_format.h b/subsys/net/lib/lwm2m/lwm2m_rw_link_format.h
new file mode 100644
index 0000000000000000000000000000000000000000..78bf872f8055f3ced7053e51f5da7074bfd5d4e5
--- /dev/null
+++ b/subsys/net/lib/lwm2m/lwm2m_rw_link_format.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef LWM2M_RW_LINK_FORMAT_H_
+#define LWM2M_RW_LINK_FORMAT_H_
+
+#include "lwm2m_object.h"
+
+extern const struct lwm2m_writer link_format_writer;
+
+int do_discover_op_link_format(struct lwm2m_message *msg, bool is_bootstrap);
+int do_register_op_link_format(struct lwm2m_message *msg);
+
+#endif /* LWM2M_RW_LINK_FORMAT_H_ */
diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c
index 154922f5b156baf17739e9250ba98f6085008697..cc62a69fb7c74c9762ae509ab4b1247d26845ee4 100644
--- a/subsys/net/lib/sockets/sockets.c
+++ b/subsys/net/lib/sockets/sockets.c
@@ -966,13 +966,31 @@ static inline ssize_t zsock_recv_dgram(struct net_context *ctx,
 	net_pkt_cursor_backup(pkt, &backup);
 
 	if (src_addr && addrlen) {
-		int rv;
-
-		rv = sock_get_pkt_src_addr(pkt, net_context_get_ip_proto(ctx),
-					   src_addr, *addrlen);
-		if (rv < 0) {
-			errno = -rv;
-			goto fail;
+		if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
+		    net_if_is_ip_offloaded(net_context_get_iface(ctx))) {
+			/*
+			 * Packets from offloaded IP stack do not have IP
+			 * headers, so src address cannot be figured out at this
+			 * point. The best we can do is returning remote address
+			 * if that was set using connect() call.
+			 */
+			if (ctx->flags & NET_CONTEXT_REMOTE_ADDR_SET) {
+				memcpy(src_addr, &ctx->remote,
+				       MIN(*addrlen, sizeof(ctx->remote)));
+			} else {
+				errno = ENOTSUP;
+				goto fail;
+			}
+		} else {
+			int rv;
+
+			rv = sock_get_pkt_src_addr(pkt, net_context_get_ip_proto(ctx),
+						   src_addr, *addrlen);
+			if (rv < 0) {
+				errno = -rv;
+				LOG_ERR("sock_get_pkt_src_addr %d", rv);
+				goto fail;
+			}
 		}
 
 		/* addrlen is a value-result argument, set to actual
diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c
index 7655c132ab7e6263e54e5aa4e18a133dd79b223d..c063829e3e62d8b7b55c9a7854fa44c1eca8621a 100644
--- a/subsys/shell/shell.c
+++ b/subsys/shell/shell.c
@@ -1249,7 +1249,7 @@ void shell_thread(void *shell_handle, void *arg_log_backend,
 		return;
 	}
 
-	if (log_backend && IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
+	if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND) && log_backend) {
 		z_shell_log_backend_enable(shell->log_backend, (void *)shell,
 					   log_level);
 	}
diff --git a/tests/benchmarks/footprints/prj.conf b/tests/benchmarks/footprints/prj.conf
index 60c938a1b1fc45a4a6a36dbc4c35dd8b5417285c..0b59ae6b7841d77e7bc95fa66c25b138adea1f6e 100644
--- a/tests/benchmarks/footprints/prj.conf
+++ b/tests/benchmarks/footprints/prj.conf
@@ -1,6 +1,5 @@
+CONFIG_TEST=y
 CONFIG_HEAP_MEM_POOL_SIZE=256
 CONFIG_MAIN_STACK_SIZE=2048
 CONFIG_MP_NUM_CPUS=1
-CONFIG_LOG=y
-CONFIG_LOG_MODE_MINIMAL=y
 CONFIG_THREAD_NAME=y
diff --git a/tests/benchmarks/mbedtls/prj.conf b/tests/benchmarks/mbedtls/prj.conf
index a930c945879c24d34b51a9b0efd5cd31671d6ae3..93133b53480fd20bc94f91e876d29806e28d5744 100644
--- a/tests/benchmarks/mbedtls/prj.conf
+++ b/tests/benchmarks/mbedtls/prj.conf
@@ -1,3 +1,5 @@
+CONFIG_TEST=y
+
 # Kernel options
 CONFIG_MAIN_STACK_SIZE=10000
 CONFIG_ENTROPY_GENERATOR=y
diff --git a/tests/benchmarks/sched/prj.conf b/tests/benchmarks/sched/prj.conf
index 2871aaa05bee013a7b883dca72f100ac78cf0eba..c7a5efd8f43ba8e98100b0a18c2538e3b88a0be9 100644
--- a/tests/benchmarks/sched/prj.conf
+++ b/tests/benchmarks/sched/prj.conf
@@ -1,3 +1,4 @@
+CONFIG_TEST=y
 CONFIG_NUM_PREEMPT_PRIORITIES=8
 CONFIG_NUM_COOP_PRIORITIES=8
 
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/CMakeLists.txt b/tests/bluetooth/bsim_bt/bsim_test_mesh/CMakeLists.txt
index 8b333e3eef0b32f72879cc254d269ba523879dad..ce2378bf2a4b063cd22a3edd46e7b261533b71aa 100644
--- a/tests/bluetooth/bsim_bt/bsim_test_mesh/CMakeLists.txt
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/CMakeLists.txt
@@ -16,6 +16,7 @@ target_sources(app PRIVATE
 	src/main.c
 	src/mesh_test.c
 	src/test_transport.c
+	src/test_friendship.c
 )
 
 zephyr_include_directories(
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/prj.conf b/tests/bluetooth/bsim_bt/bsim_test_mesh/prj.conf
index 1ff1727cf807a2477d7a9236956996bdc54a5670..7bca23b3f3d2cb4c8842d4fb507bb7cc9781afe0 100644
--- a/tests/bluetooth/bsim_bt/bsim_test_mesh/prj.conf
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/prj.conf
@@ -25,7 +25,12 @@ CONFIG_BT_MESH_RX_SEG_MAX=32
 CONFIG_BT_MESH_TX_SEG_MSG_COUNT=10
 CONFIG_BT_MESH_RX_SEG_MSG_COUNT=10
 CONFIG_BT_MESH_CFG_CLI=y
-CONFIG_BT_MESH_MODEL_GROUP_COUNT=2
+CONFIG_BT_MESH_MODEL_GROUP_COUNT=3
+CONFIG_BT_MESH_LOW_POWER=y
+CONFIG_BT_MESH_LPN_AUTO=n
+CONFIG_BT_MESH_FRIEND=y
+CONFIG_BT_MESH_FRIEND_ENABLED=n
+CONFIG_BT_MESH_FRIEND_LPN_COUNT=5
 CONFIG_BT_MESH_APP_KEY_COUNT=2
 CONFIG_BT_MESH_MODEL_KEY_COUNT=2
 CONFIG_BT_MESH_IV_UPDATE_TEST=y
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/src/main.c b/tests/bluetooth/bsim_bt/bsim_test_mesh/src/main.c
index ab4138f88767fe580634bd975f9226d121e6b3af..2a1deaa8c4bea2c9480d2c4b7f0182d8857a244d 100644
--- a/tests/bluetooth/bsim_bt/bsim_test_mesh/src/main.c
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/src/main.c
@@ -9,9 +9,11 @@
 
 extern struct bst_test_list *
 test_transport_install(struct bst_test_list *tests);
+struct bst_test_list *test_friendship_install(struct bst_test_list *tests);
 
 bst_test_install_t test_installers[] = {
 	test_transport_install,
+	test_friendship_install,
 	NULL
 };
 
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/src/test_friendship.c b/tests/bluetooth/bsim_bt/bsim_test_mesh/src/test_friendship.c
new file mode 100644
index 0000000000000000000000000000000000000000..1493c8f5a56013a89758b976524866db489007d4
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/src/test_friendship.c
@@ -0,0 +1,841 @@
+/*
+ * Copyright (c) 2021 Nordic Semiconductor
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "mesh_test.h"
+#include "mesh/net.h"
+#include "mesh/transport.h"
+#include <sys/byteorder.h>
+
+#define LOG_MODULE_NAME test_friendship
+
+#include <logging/log.h>
+LOG_MODULE_REGISTER(LOG_MODULE_NAME);
+
+/*
+ * Friendship tests:
+ *   Tests both the friend and the low power role in various scenarios.
+ */
+
+#define GROUP_ADDR 0xc000
+#define WAIT_TIME 60 /*seconds*/
+#define LPN_ADDR_START 0x0003
+#define POLL_TIMEOUT_MS (100 * CONFIG_BT_MESH_LPN_POLL_TIMEOUT)
+
+extern enum bst_result_t bst_result;
+
+enum test_flags {
+	LPN_ESTABLISHED,
+	LPN_TERMINATED,
+	LPN_POLLED,
+	FRIEND_ESTABLISHED,
+	FRIEND_TERMINATED,
+	FRIEND_POLLED,
+
+	TEST_FLAGS,
+};
+
+static ATOMIC_DEFINE(state, TEST_FLAGS);
+static struct k_sem events[TEST_FLAGS];
+
+static const struct bt_mesh_test_cfg friend_cfg = {
+	.addr = 0x0001,
+	.dev_key = { 0x01 },
+};
+static const struct bt_mesh_test_cfg other_cfg = {
+	.addr = 0x0002,
+	.dev_key = { 0x02 },
+};
+static struct bt_mesh_test_cfg lpn_cfg;
+static uint16_t friend_lpn_addr;
+
+static void test_common_init(const struct bt_mesh_test_cfg *cfg)
+{
+	for (int i = 0; i < ARRAY_SIZE(events); i++) {
+		k_sem_init(&events[i], 0, 1);
+	}
+
+	bt_mesh_test_cfg_set(cfg, WAIT_TIME);
+}
+
+static void test_friend_init(void)
+{
+	test_common_init(&friend_cfg);
+}
+
+static void test_lpn_init(void)
+{
+	/* As there may be multiple LPN devices, we'll set the address and
+	 * devkey based on the device number, which is guaranteed to be unique
+	 * for each device in the simulation.
+	 */
+	extern uint global_device_nbr;
+
+	lpn_cfg.addr = LPN_ADDR_START + global_device_nbr;
+	lpn_cfg.dev_key[0] = global_device_nbr;
+	test_common_init(&lpn_cfg);
+}
+
+static void test_other_init(void)
+{
+	test_common_init(&other_cfg);
+}
+
+static void evt_signal(enum test_flags evt)
+{
+	atomic_set_bit(state, evt);
+	k_sem_give(&events[evt]);
+}
+
+static int evt_wait(enum test_flags evt, k_timeout_t timeout)
+{
+	return k_sem_take(&events[evt], timeout);
+}
+
+static void evt_clear(enum test_flags evt)
+{
+	atomic_clear_bit(state, evt);
+	k_sem_reset(&events[evt]);
+}
+
+static void friend_established(uint16_t net_idx, uint16_t lpn_addr,
+			    uint8_t recv_delay, uint32_t polltimeout)
+{
+	LOG_INF("Friend: established with 0x%04x", lpn_addr);
+	friend_lpn_addr = lpn_addr;
+	evt_signal(FRIEND_ESTABLISHED);
+}
+
+static void friend_terminated(uint16_t net_idx, uint16_t lpn_addr)
+{
+	LOG_INF("Friend: terminated with 0x%04x", lpn_addr);
+	evt_signal(FRIEND_TERMINATED);
+}
+
+static void friend_polled(uint16_t net_idx, uint16_t lpn_addr)
+{
+	LOG_INF("Friend: Poll from 0x%04x", lpn_addr);
+	evt_signal(FRIEND_POLLED);
+}
+
+BT_MESH_FRIEND_CB_DEFINE(friend) = {
+	.established = friend_established,
+	.terminated = friend_terminated,
+	.polled = friend_polled,
+};
+
+static void lpn_established(uint16_t net_idx, uint16_t friend_addr,
+			    uint8_t queue_size, uint8_t recv_window)
+{
+	LOG_INF("LPN: established with 0x%04x", friend_addr);
+	evt_signal(LPN_ESTABLISHED);
+}
+
+static void lpn_terminated(uint16_t net_idx, uint16_t friend_addr)
+{
+	LOG_INF("LPN: terminated with 0x%04x", friend_addr);
+	evt_signal(LPN_TERMINATED);
+}
+
+static void lpn_polled(uint16_t net_idx, uint16_t friend_addr, bool retry)
+{
+	LOG_INF("LPN: Polling 0x%04x (%s)", friend_addr,
+		retry ? "retry" : "initial");
+	evt_signal(LPN_POLLED);
+}
+
+BT_MESH_LPN_CB_DEFINE(lpn) = {
+	.established = lpn_established,
+	.polled = lpn_polled,
+	.terminated = lpn_terminated,
+};
+
+static void friend_wait_for_polls(int polls)
+{
+	/* Let LPN poll to get the sent message */
+	ASSERT_OK(evt_wait(FRIEND_POLLED, K_SECONDS(30)), "LPN never polled");
+
+	while (--polls) {
+		/* Wait for LPN to poll until the "no more data" message.
+		 * At this point, the message has been delivered.
+		 */
+		ASSERT_OK(evt_wait(FRIEND_POLLED, K_SECONDS(2)),
+			  "LPN missing %d polls", polls);
+	}
+
+	if (evt_wait(FRIEND_POLLED, K_SECONDS(2)) != -EAGAIN) {
+		FAIL("Unexpected extra poll");
+		return;
+	}
+}
+
+/* Friend test functions */
+
+/** Initialize as a friend and wait for the friendship to be established.
+ */
+static void test_friend_est(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_friend_set(BT_MESH_FEATURE_ENABLED);
+
+	ASSERT_OK(evt_wait(FRIEND_ESTABLISHED, K_SECONDS(5)),
+		  "Friendship not established");
+
+	PASS();
+}
+
+/** Initialize as a friend, and wait for multiple friendships to be established
+ *  concurrently.
+ *
+ *  Verify that all friendships survive the first poll timeout.
+ */
+static void test_friend_est_multi(void)
+{
+	int err;
+
+	bt_mesh_test_setup();
+
+	k_sem_init(&events[FRIEND_ESTABLISHED], 0,
+		   CONFIG_BT_MESH_FRIEND_LPN_COUNT);
+
+	bt_mesh_friend_set(BT_MESH_FEATURE_ENABLED);
+
+	for (int i = 0; i < CONFIG_BT_MESH_FRIEND_LPN_COUNT; i++) {
+		ASSERT_OK(evt_wait(FRIEND_ESTABLISHED, K_SECONDS(5)),
+			  "Friendship %d not established", i);
+	}
+
+	/* Wait for all friends to do at least one poll without terminating */
+	err = evt_wait(FRIEND_TERMINATED,
+		       K_MSEC(POLL_TIMEOUT_MS + 5 * MSEC_PER_SEC));
+	if (!err) {
+		FAIL("One or more friendships terminated");
+	}
+
+	PASS();
+}
+
+/** As a friend, send messages to the LPN.
+ *
+ *  Verifies unsegmented, segmented and multiple packet sending and receiving.
+ */
+static void test_friend_msg(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_friend_set(BT_MESH_FEATURE_ENABLED);
+
+	ASSERT_OK(evt_wait(FRIEND_ESTABLISHED, K_SECONDS(5)),
+		  "Friendship not established");
+	/* LPN polls on establishment. Clear the poll state */
+	evt_clear(FRIEND_POLLED);
+
+	k_sleep(K_SECONDS(1));
+
+	/* Send unsegmented message from friend to LPN: */
+	LOG_INF("Sending unsegmented message");
+	ASSERT_OK(bt_mesh_test_send(friend_lpn_addr, 5, 0, K_SECONDS(1)),
+		  "Unseg send failed");
+
+	/* Wait for LPN to poll for message and the "no more messages" msg */
+	friend_wait_for_polls(2);
+
+	/* Send segmented message */
+	ASSERT_OK(bt_mesh_test_send(friend_lpn_addr, 13, 0, K_SECONDS(1)),
+		  "Unseg send failed");
+
+	/* Two segments require 2 polls plus the "no more messages" msg */
+	friend_wait_for_polls(3);
+
+	/* Send two unsegmented messages before the next poll.
+	 * This tests the friend role's re-encryption mechanism for the second
+	 * message, as sending the first message through the network layer
+	 * increases the seqnum by one, creating an inconsistency between the
+	 * transport and network parts of the second packet.
+	 * Ensures coverage for the regression reported in #32033.
+	 */
+	ASSERT_OK(bt_mesh_test_send(friend_lpn_addr, 5, 0, K_SECONDS(1)),
+		  "Unseg send failed");
+	ASSERT_OK(bt_mesh_test_send(friend_lpn_addr, 5, 0, K_SECONDS(1)),
+		  "Unseg send failed");
+
+	/* Two messages require 2 polls plus the "no more messages" msg */
+	friend_wait_for_polls(3);
+
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(10)),
+		  "Receive from LPN failed");
+
+	/* Receive a segmented message from the LPN. LPN should poll for the ack
+	 * after sending the segments.
+	 */
+	ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_SECONDS(10)),
+		  "Receive from LPN failed");
+	friend_wait_for_polls(2);
+
+	PASS();
+}
+
+/** As a friend, overflow the message queue for the LPN with own packets.
+ *
+ *  Verify that the LPN doesn't terminate the friendship during the poll for
+ *  messages.
+ */
+static void test_friend_overflow(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_friend_set(BT_MESH_FEATURE_ENABLED);
+
+	ASSERT_OK(evt_wait(FRIEND_ESTABLISHED, K_SECONDS(5)),
+		  "Friendship not established");
+	evt_clear(FRIEND_POLLED);
+
+	k_sleep(K_SECONDS(3));
+
+	/* Fill the queue */
+	for (int i = 0; i < CONFIG_BT_MESH_FRIEND_QUEUE_SIZE; i++) {
+		bt_mesh_test_send(friend_lpn_addr, 5, 0, K_NO_WAIT);
+	}
+
+	/* Add one more message, which should overflow the queue and cause the
+	 * first message to be discarded.
+	 */
+	bt_mesh_test_send(friend_lpn_addr, 5, 0, K_NO_WAIT);
+
+	ASSERT_OK(evt_wait(FRIEND_POLLED, K_SECONDS(35)),
+		  "Friend never polled");
+
+	if (atomic_test_bit(state, FRIEND_TERMINATED)) {
+		FAIL("Friendship terminated unexpectedly");
+	}
+
+	PASS();
+}
+
+/** Establish a friendship, wait for communication between the LPN and a mesh
+ *  device to finish, then send group and virtual addr messages to the LPN.
+ *  Let the LPN add another group message, then send to that as well.
+ */
+static void test_friend_group(void)
+{
+	uint16_t virtual_addr;
+
+	bt_mesh_test_setup();
+
+	bt_mesh_friend_set(BT_MESH_FEATURE_ENABLED);
+
+	ASSERT_OK(evt_wait(FRIEND_ESTABLISHED, K_SECONDS(5)),
+		  "Friendship not established");
+	evt_clear(FRIEND_POLLED);
+
+	ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr));
+
+	/* The other mesh device will send its messages in the first poll */
+	ASSERT_OK(evt_wait(FRIEND_POLLED, K_SECONDS(10)));
+
+	k_sleep(K_SECONDS(2));
+
+	/* Send a group message to the LPN */
+	ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)),
+		  "Failed to send to LPN");
+	/* Send a virtual message to the LPN */
+	ASSERT_OK(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)),
+		  "Failed to send to LPN");
+
+	/* Wait for the LPN to poll for each message, then for adding the
+	 * group address:
+	 */
+	friend_wait_for_polls(3);
+
+	/* Send a group message to an address the LPN added after the friendship
+	 * was established.
+	 */
+	ASSERT_OK(bt_mesh_test_send(GROUP_ADDR + 1, 5, 0, K_SECONDS(1)),
+		  "Failed to send to LPN");
+
+	evt_wait(FRIEND_POLLED, K_SECONDS(10));
+
+	PASS();
+}
+
+/* LPN test functions */
+
+/** Enable the LPN role, and verify that the friendship is established.
+ *
+ *  Verify that the friendship survives the first poll timeout.
+ */
+static void test_lpn_est(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_lpn_set(true);
+
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(5)),
+		  "LPN not established");
+	if (!evt_wait(LPN_TERMINATED,
+		      K_MSEC(POLL_TIMEOUT_MS + 5 * MSEC_PER_SEC))) {
+		FAIL("Friendship terminated unexpectedly");
+	}
+
+	PASS();
+}
+
+/** As an LPN, exchange messages with the friend node.
+ *
+ *  Verifies sending and receiving of unsegmented, segmented and multiple
+ *  messages to and from the connected friend node.
+ */
+static void test_lpn_msg_frnd(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_lpn_set(true);
+
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(5)),
+		  "LPN not established");
+	/* LPN polls on establishment. Clear the poll state */
+	evt_clear(LPN_POLLED);
+
+	/* Give friend time to prepare the message */
+	k_sleep(K_SECONDS(2));
+
+	/* Receive unsegmented message */
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)),
+		  "Failed to receive message");
+
+	/* Give friend time to prepare the message */
+	k_sleep(K_SECONDS(2));
+
+	/* Receive segmented message */
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+	ASSERT_OK(bt_mesh_test_recv(13, cfg->addr, K_SECONDS(2)),
+		  "Failed to receive message");
+
+	/* Give friend time to prepare the messages */
+	k_sleep(K_SECONDS(3));
+
+	/* Receive two unsegmented messages */
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(2)),
+		  "Failed to receive message");
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(2)),
+		  "Failed to receive message");
+
+	k_sleep(K_SECONDS(3));
+
+	/* Send an unsegmented message to the friend.
+	 * Should not be affected by the LPN mode at all.
+	 */
+	ASSERT_OK(bt_mesh_test_send(friend_cfg.addr, 5, 0, K_MSEC(500)),
+		  "Send to friend failed");
+
+	k_sleep(K_SECONDS(5));
+
+	/* Send a segmented message to the friend. Should trigger a poll for the
+	 * ack.
+	 */
+	ASSERT_OK(bt_mesh_test_send(friend_cfg.addr, 15, 0, K_SECONDS(5)),
+		  "Send to friend failed");
+
+	PASS();
+}
+
+/** As an LPN, exchange messages with a third party mesh node while in a
+ *  friendship.
+ *
+ *  Verifies sending and receiving of unsegmented and segmented messages to and
+ *  from the third party node.
+ */
+static void test_lpn_msg_mesh(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_lpn_set(true);
+
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(2)),
+		  "LPN not established");
+	/* LPN polls on establishment. Clear the poll state */
+	evt_clear(LPN_POLLED);
+
+	/* Send an unsegmented message to a third mesh node.
+	 * Should not be affected by the LPN mode at all.
+	 */
+	ASSERT_OK(bt_mesh_test_send(other_cfg.addr, 5, 0, K_MSEC(500)),
+		  "Send to mesh failed");
+
+	/* Receive an unsegmented message back */
+	k_sleep(K_SECONDS(1));
+	ASSERT_OK(bt_mesh_lpn_poll());
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(2)));
+
+	k_sleep(K_SECONDS(1));
+
+	/* Send a segmented message to the mesh node.
+	 * Should trigger a poll for the ack.
+	 */
+	ASSERT_OK(bt_mesh_test_send(other_cfg.addr, 15, 0, K_SECONDS(5)),
+		  "Send to other failed");
+
+	/* Receive a segmented message back */
+	k_sleep(K_SECONDS(1));
+	ASSERT_OK(bt_mesh_lpn_poll());
+	ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_SECONDS(5)));
+
+	/* Send an unsegmented message with friend credentials to a third mesh
+	 * node. The friend shall relay it.
+	 */
+	test_model->pub->addr = other_cfg.addr;
+	test_model->pub->cred = true; /* Use friend credentials */
+	test_model->pub->ttl = BT_MESH_TTL_DEFAULT;
+
+	net_buf_simple_reset(test_model->pub->msg);
+	bt_mesh_model_msg_init(test_model->pub->msg, TEST_MSG_OP);
+	ASSERT_OK(bt_mesh_model_publish(test_model));
+
+	PASS();
+}
+
+/** As an LPN, establish and terminate a friendship with the same friend
+ *  multiple times in a row to ensure that both parties are able to recover.
+ */
+static void test_lpn_re_est(void)
+{
+	bt_mesh_test_setup();
+
+	for (int i = 0; i < 4; i++) {
+		bt_mesh_lpn_set(true);
+		ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(2)),
+			"LPN not established");
+
+		bt_mesh_lpn_set(false);
+		ASSERT_OK(evt_wait(LPN_TERMINATED, K_SECONDS(5)),
+			"LPN never terminated friendship");
+
+		k_sleep(K_SECONDS(2));
+	}
+
+	PASS();
+}
+
+/** Establish a friendship as an LPN, and verify that the friendship survives
+ *  the first poll timeout without terminating
+ */
+static void test_lpn_poll(void)
+{
+	bt_mesh_test_setup();
+
+	bt_mesh_lpn_set(true);
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(5)),
+		  "LPN not established");
+	evt_clear(LPN_POLLED);
+
+	ASSERT_OK(evt_wait(LPN_POLLED, K_MSEC(POLL_TIMEOUT_MS)),
+		  "LPN failed to poll before the timeout");
+
+	k_sleep(K_SECONDS(10));
+	if (atomic_test_bit(state, LPN_TERMINATED)) {
+		FAIL("LPN terminated.");
+	}
+
+	PASS();
+}
+
+/** Receive packets from a friend that overflowed its queue. Verify that the
+ *  first packet is discarded because of the overflow.
+ */
+static void test_lpn_overflow(void)
+{
+	struct bt_mesh_test_msg msg;
+	int err;
+
+	bt_mesh_test_setup();
+
+	bt_mesh_lpn_set(true);
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(5)),
+		  "LPN not established");
+	evt_clear(LPN_POLLED);
+
+	k_sleep(K_SECONDS(5));
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+
+	for (int i = 0; i < CONFIG_BT_MESH_FRIEND_QUEUE_SIZE; i++) {
+		ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(2)),
+			  "Receive %d failed", i);
+
+		if (msg.len != 5) {
+			FAIL("Message %d: Invalid length %d", i, msg.len);
+		}
+
+		if (msg.ctx.recv_dst != cfg->addr) {
+			FAIL("Message %d: Invalid dst 0x%04x", i,
+			     msg.ctx.recv_dst);
+		}
+
+		/* The first message (with seq=1) should have been discarded by
+		 * the friend, so the first message should have seq=2:
+		 */
+		if (msg.seq != i + 2) {
+			FAIL("Message %d: Invalid seq 0x%02x", i, msg.seq);
+		}
+	}
+
+	/* Not expecting any more messages from friend */
+	err = bt_mesh_test_recv_msg(&msg, K_SECONDS(10));
+	if (!err) {
+		FAIL("Unexpected additional message 0x%02x from 0x%04x",
+		     msg.seq, msg.ctx.addr);
+	}
+
+	PASS();
+}
+
+/** As an LPN, receive packets on group and virtual addresses from mesh device
+ *  and friend. Then, add a second group address (while the friendship is
+ *  established), and receive on that as well.
+ */
+static void test_lpn_group(void)
+{
+	struct bt_mesh_test_msg msg;
+	uint16_t vaddr;
+	uint8_t status = 0;
+	int err;
+
+	bt_mesh_test_setup();
+
+	err = bt_mesh_cfg_mod_sub_add(0, cfg->addr, cfg->addr, GROUP_ADDR,
+				      TEST_MOD_ID, &status);
+	if (err || status) {
+		FAIL("Group addr add failed with err %d status 0x%x", err,
+		     status);
+	}
+
+	err = bt_mesh_cfg_mod_sub_va_add(0, cfg->addr, cfg->addr, test_va_uuid,
+					 TEST_MOD_ID, &vaddr, &status);
+	if (err || status) {
+		FAIL("VA addr add failed with err %d status 0x%x", err, status);
+	}
+
+	bt_mesh_lpn_set(true);
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(5)),
+		  "LPN not established");
+	evt_clear(LPN_POLLED);
+
+	k_sleep(K_SECONDS(5));
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+
+	/* From other device */
+	ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
+	if (msg.ctx.recv_dst != GROUP_ADDR || msg.ctx.addr != other_cfg.addr) {
+		FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
+		     msg.ctx.recv_dst);
+	}
+
+	ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
+	if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != other_cfg.addr) {
+		FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
+		     msg.ctx.recv_dst);
+	}
+
+	k_sleep(K_SECONDS(5));
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+
+	/* From friend */
+	ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
+	if (msg.ctx.recv_dst != GROUP_ADDR || msg.ctx.addr != friend_cfg.addr) {
+		FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
+		     msg.ctx.recv_dst);
+	}
+
+	ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
+	if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != friend_cfg.addr) {
+		FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
+		     msg.ctx.recv_dst);
+	}
+
+	k_sleep(K_SECONDS(1));
+
+	LOG_INF("Adding second group addr");
+
+	/* Add a new group addr, then receive on it to ensure that the friend
+	 * has added it to the subscription list.
+	 */
+	err = bt_mesh_cfg_mod_sub_add(0, cfg->addr, cfg->addr, GROUP_ADDR + 1,
+				      TEST_MOD_ID, &status);
+	if (err || status) {
+		FAIL("Group addr add failed with err %d status 0x%x", err,
+		     status);
+	}
+
+	k_sleep(K_SECONDS(5));
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+
+	/* From friend on second group address */
+	ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
+	if (msg.ctx.recv_dst != GROUP_ADDR + 1 ||
+	    msg.ctx.addr != friend_cfg.addr) {
+		FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
+		     msg.ctx.recv_dst);
+	}
+
+	PASS();
+}
+
+/** As an LPN, send packets to own address to ensure that this is handled by
+ *  loopback mechanism, and ignored by friend.
+ *
+ *  Adds test coverage for regression in #30657.
+ */
+static void test_lpn_loopback(void)
+{
+	struct bt_mesh_test_msg msg;
+	uint16_t vaddr;
+	uint8_t status = 0;
+	int err;
+
+	bt_mesh_test_setup();
+
+	err = bt_mesh_cfg_mod_sub_add(0, cfg->addr, cfg->addr, GROUP_ADDR,
+				      TEST_MOD_ID, &status);
+	if (err || status) {
+		FAIL("Group addr add failed with err %d status 0x%x", err,
+		     status);
+	}
+
+	err = bt_mesh_cfg_mod_sub_va_add(0, cfg->addr, cfg->addr, test_va_uuid,
+					 TEST_MOD_ID, &vaddr, &status);
+	if (err || status) {
+		FAIL("VA addr add failed with err %d status 0x%x", err, status);
+	}
+
+	bt_mesh_lpn_set(true);
+	ASSERT_OK(evt_wait(LPN_ESTABLISHED, K_SECONDS(5)),
+		  "LPN not established");
+	evt_clear(LPN_POLLED);
+
+	k_sleep(K_SECONDS(1));
+
+	/* Loopback on unicast, shouldn't even leave the device */
+	ASSERT_OK(bt_mesh_test_send_async(cfg->addr, 5, 0, NULL, NULL));
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)));
+
+	/* Loopback on group address, should not come back from the friend */
+	ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, 5, 0, NULL, NULL));
+	ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, K_SECONDS(1)));
+
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+	err = bt_mesh_test_recv_msg(&msg, K_SECONDS(2));
+	if (err != -ETIMEDOUT) {
+		FAIL("Unexpected receive status: %d", err);
+	}
+
+	/* Loopback on virtual address, should not come back from the friend */
+	ASSERT_OK(bt_mesh_test_send_async(vaddr, 5, 0, NULL, NULL));
+	ASSERT_OK(bt_mesh_test_recv(5, vaddr, K_SECONDS(1)));
+
+	k_sleep(K_SECONDS(2));
+
+	/* Poll the friend and make sure we don't receive any messages: */
+	ASSERT_OK(bt_mesh_lpn_poll(), "Poll failed");
+	err = bt_mesh_test_recv_msg(&msg, K_SECONDS(5));
+	if (err != -ETIMEDOUT) {
+		FAIL("Unexpected receive status: %d", err);
+	}
+
+	PASS();
+}
+
+/* Mesh device test functions */
+
+/** Without engaging in a friendship, communicate with an LPN through a friend
+ *  node.
+ */
+static void test_other_msg(void)
+{
+	bt_mesh_test_setup();
+
+	/* Receive an unsegmented message from the LPN. */
+	ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(4)),
+		  "Failed to receive from LPN");
+
+	/* Send an unsegmented message to the LPN */
+	ASSERT_OK(bt_mesh_test_send(LPN_ADDR_START, 5, 0, K_SECONDS(1)),
+		  "Failed to send to LPN");
+
+	/* Receive a segmented message from the LPN. */
+	ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_SECONDS(10)),
+		  "Failed to receive from LPN");
+
+	/* Send a segmented message to the friend. Should trigger a poll for the
+	 * ack.
+	 */
+	ASSERT_OK(bt_mesh_test_send(LPN_ADDR_START, 15, 0, K_SECONDS(10)),
+		  "Send to LPN failed");
+
+	/* Receive an unsegmented message from the LPN, originally sent with
+	 * friend credentials.
+	 */
+	ASSERT_OK(bt_mesh_test_recv(1, cfg->addr, K_SECONDS(10)),
+		  "Failed to receive from LPN");
+
+	PASS();
+}
+
+/** Without engaging in a friendship, send group and virtual addr messages to
+ *  the LPN.
+ */
+static void test_other_group(void)
+{
+	uint16_t virtual_addr;
+
+	bt_mesh_test_setup();
+
+	ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr));
+
+	/* Send a group message to the LPN */
+	ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)),
+		  "Failed to send to LPN");
+	/* Send a virtual message to the LPN */
+	ASSERT_OK(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)),
+		  "Failed to send to LPN");
+
+	PASS();
+}
+
+#define TEST_CASE(role, name, description)                                     \
+	{                                                                      \
+		.test_id = "friendship_" #role "_" #name,                      \
+		.test_descr = description,                                     \
+		.test_post_init_f = test_##role##_init,                        \
+		.test_tick_f = bt_mesh_test_timeout,                           \
+		.test_main_f = test_##role##_##name,                           \
+	}
+
+static const struct bst_test_instance test_connect[] = {
+	TEST_CASE(friend, est,       "Friend: establish friendship"),
+	TEST_CASE(friend, est_multi, "Friend: establish multiple friendships"),
+	TEST_CASE(friend, msg,       "Friend: message exchange"),
+	TEST_CASE(friend, overflow,  "Friend: message queue overflow"),
+	TEST_CASE(friend, group,     "Friend: send to group addrs"),
+
+	TEST_CASE(lpn,    est,       "LPN: establish friendship"),
+	TEST_CASE(lpn,    msg_frnd,  "LPN: message exchange with friend"),
+	TEST_CASE(lpn,    msg_mesh,  "LPN: message exchange with mesh"),
+	TEST_CASE(lpn,    re_est,    "LPN: re-establish friendship"),
+	TEST_CASE(lpn,    poll,      "LPN: poll before timeout"),
+	TEST_CASE(lpn,    overflow,  "LPN: message queue overflow"),
+	TEST_CASE(lpn,    group,     "LPN: receive on group addrs"),
+	TEST_CASE(lpn,    loopback,  "LPN: send to loopback addrs"),
+
+	TEST_CASE(other,  msg,       "Other mesh device: message exchange"),
+	TEST_CASE(other,  group,     "Other mesh device: send to group addrs"),
+	BSTEST_END_MARKER
+};
+
+struct bst_test_list *test_friendship_install(struct bst_test_list *tests)
+{
+	tests = bst_add_tests(tests, test_connect);
+	return tests;
+}
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/establish.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/establish.sh
new file mode 100755
index 0000000000000000000000000000000000000000..34f950d1128936b7382a4b8dd22f6b6c8008951a
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/establish.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Establish a single friendship, wait for first poll timeout
+RunTest mesh_friendship_establish \
+	friendship_friend_est \
+	friendship_lpn_est
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/establish_multi.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/establish_multi.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c63c7b7ae6da66a0cca3bf21423fd013defde966
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/establish_multi.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Establish multiple different friendships concurrently.
+# Note: The number of LPNs must match CONFIG_BT_MESH_FRIEND_LPN_COUNT.
+RunTest mesh_friendship_establish_multi \
+	friendship_friend_est_multi \
+	friendship_lpn_est \
+	friendship_lpn_est \
+	friendship_lpn_est \
+	friendship_lpn_est \
+	friendship_lpn_est
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/lpn_loopback.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/lpn_loopback.sh
new file mode 100755
index 0000000000000000000000000000000000000000..00d0b755d0b8241f0588df69b585aaad1d5b1d61
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/lpn_loopback.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test LPN sending packets to a group and virtual address it subscribes to
+RunTest mesh_friendship_lpn_loopback \
+	friendship_lpn_loopback \
+	friendship_friend_est \
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_frnd.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_frnd.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6449a95876ad662530b5ef6893169c760e390947
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_frnd.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Send messages from the friend to the LPN
+RunTest mesh_friendship_msg_frnd \
+	friendship_friend_msg \
+	friendship_lpn_msg_frnd
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_group.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_group.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c092e01e6655b1e301902dc46d10579622af2c67
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_group.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test receieves on group and virtual addresses in the LPN
+RunTest mesh_friendship_msg_group \
+	friendship_lpn_group \
+	friendship_other_group \
+	friendship_friend_group \
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_mesh.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_mesh.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f0225f25a21d15798219d1b97ee9d4b0c2a5221f
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/msg_mesh.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test communication between the LPN and a third mesh device
+RunTest mesh_friendship_msg_mesh \
+	friendship_lpn_msg_mesh \
+	friendship_other_msg \
+	friendship_friend_est \
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/overflow.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/overflow.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c24bda95e071497f415617581df8d15046782b20
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/overflow.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test friend queue overflow
+RunTest mesh_friendship_overflow \
+	friendship_friend_overflow \
+	friendship_lpn_overflow
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/poll.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/poll.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f8eead190d028ee3faf79396ca94e43f6351a105
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/poll.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test poll timeout
+RunTest mesh_friendship_poll \
+	friendship_friend_est \
+	friendship_lpn_poll
diff --git a/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/re-establish.sh b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/re-establish.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1e78219083aab85e5d9b10ee166fcb381a3b1f27
--- /dev/null
+++ b/tests/bluetooth/bsim_bt/bsim_test_mesh/tests_scripts/friendship/re-establish.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Copyright 2021 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test friendship re-establishment
+RunTest mesh_friendship_re_establish \
+	friendship_friend_est \
+	friendship_lpn_re_est
diff --git a/tests/bluetooth/init/prj_ctlr_central_ext_priv.conf b/tests/bluetooth/init/prj_ctlr_central_ext_priv.conf
new file mode 100644
index 0000000000000000000000000000000000000000..59f8a46addb4c773c4642f50e3cce431fe375918
--- /dev/null
+++ b/tests/bluetooth/init/prj_ctlr_central_ext_priv.conf
@@ -0,0 +1,12 @@
+CONFIG_BT=y
+CONFIG_BT_CTLR=y
+CONFIG_BT_BROADCASTER=n
+CONFIG_BT_PERIPHERAL=n
+CONFIG_BT_OBSERVER=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_SMP=y
+CONFIG_BT_PRIVACY=y
+CONFIG_BT_EXT_ADV=y
+CONFIG_BT_CTLR_ADV_EXT=y
+CONFIG_BT_LL_SW_SPLIT=y
+CONFIG_ZTEST=y
diff --git a/tests/bluetooth/init/prj_ctlr_central_priv.conf b/tests/bluetooth/init/prj_ctlr_central_priv.conf
new file mode 100644
index 0000000000000000000000000000000000000000..3bf4650f1e7f919b1ff00a28abaf8625134d5dbe
--- /dev/null
+++ b/tests/bluetooth/init/prj_ctlr_central_priv.conf
@@ -0,0 +1,12 @@
+CONFIG_BT=y
+CONFIG_BT_CTLR=y
+CONFIG_BT_BROADCASTER=n
+CONFIG_BT_PERIPHERAL=n
+CONFIG_BT_OBSERVER=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_SMP=y
+CONFIG_BT_PRIVACY=y
+CONFIG_BT_EXT_ADV=n
+CONFIG_BT_CTLR_ADV_EXT=n
+CONFIG_BT_LL_SW_SPLIT=y
+CONFIG_ZTEST=y
diff --git a/tests/bluetooth/init/prj_ctlr_peripheral_ext_priv.conf b/tests/bluetooth/init/prj_ctlr_peripheral_ext_priv.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e0c3f9487c0e48f1d641a7261f65670c645e78bf
--- /dev/null
+++ b/tests/bluetooth/init/prj_ctlr_peripheral_ext_priv.conf
@@ -0,0 +1,12 @@
+CONFIG_BT=y
+CONFIG_BT_CTLR=y
+CONFIG_BT_BROADCASTER=y
+CONFIG_BT_PERIPHERAL=y
+CONFIG_BT_OBSERVER=n
+CONFIG_BT_CENTRAL=n
+CONFIG_BT_SMP=y
+CONFIG_BT_PRIVACY=y
+CONFIG_BT_EXT_ADV=y
+CONFIG_BT_CTLR_ADV_EXT=y
+CONFIG_BT_LL_SW_SPLIT=y
+CONFIG_ZTEST=y
diff --git a/tests/bluetooth/init/prj_ctlr_peripheral_priv.conf b/tests/bluetooth/init/prj_ctlr_peripheral_priv.conf
new file mode 100644
index 0000000000000000000000000000000000000000..9175c302272dfca0f808662ef54e4cdf5ec3da6c
--- /dev/null
+++ b/tests/bluetooth/init/prj_ctlr_peripheral_priv.conf
@@ -0,0 +1,12 @@
+CONFIG_BT=y
+CONFIG_BT_CTLR=y
+CONFIG_BT_BROADCASTER=y
+CONFIG_BT_PERIPHERAL=y
+CONFIG_BT_OBSERVER=n
+CONFIG_BT_CENTRAL=n
+CONFIG_BT_SMP=y
+CONFIG_BT_PRIVACY=y
+CONFIG_BT_EXT_ADV=n
+CONFIG_BT_CTLR_ADV_EXT=n
+CONFIG_BT_LL_SW_SPLIT=y
+CONFIG_ZTEST=y
diff --git a/tests/bluetooth/init/testcase.yaml b/tests/bluetooth/init/testcase.yaml
index c186493ee0f02d2c1124834e055242617ed903a7..d878616e1e3a0119b88dac8e028c691f4c6604a4 100644
--- a/tests/bluetooth/init/testcase.yaml
+++ b/tests/bluetooth/init/testcase.yaml
@@ -97,6 +97,10 @@ tests:
     extra_args: CONF_FILE=prj_ctlr_peripheral.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
       nrf51dk_nrf51422 rv32m1_vega_ri5cy
+  bluetooth.init.test_ctlr_peripheral_priv:
+    extra_args: CONF_FILE=prj_ctlr_peripheral_priv.conf
+    platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
+      nrf51dk_nrf51422 rv32m1_vega_ri5cy
   bluetooth.init.test_ctlr_observer:
     extra_args: CONF_FILE=prj_ctlr_observer.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
@@ -105,6 +109,10 @@ tests:
     extra_args: CONF_FILE=prj_ctlr_central.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
       nrf51dk_nrf51422 rv32m1_vega_ri5cy
+  bluetooth.init.test_ctlr_central_priv:
+    extra_args: CONF_FILE=prj_ctlr_central_priv.conf
+    platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
+      nrf51dk_nrf51422 rv32m1_vega_ri5cy
   bluetooth.init.test_ctlr_broadcaster_ext:
     extra_args: CONF_FILE=prj_ctlr_broadcaster_ext.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
@@ -113,6 +121,10 @@ tests:
     extra_args: CONF_FILE=prj_ctlr_peripheral_ext.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
       nrf51dk_nrf51422
+  bluetooth.init.test_ctlr_peripheral_ext_priv:
+    extra_args: CONF_FILE=prj_ctlr_peripheral_ext_priv.conf
+    platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
+      nrf51dk_nrf51422
   bluetooth.init.test_ctlr_oberver_ext:
     extra_args: CONF_FILE=prj_ctlr_observer_ext.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
@@ -121,6 +133,10 @@ tests:
     extra_args: CONF_FILE=prj_ctlr_central_ext.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
       nrf51dk_nrf51422
+  bluetooth.init.test_ctlr_central_ext_priv:
+    extra_args: CONF_FILE=prj_ctlr_central_ext_priv.conf
+    platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
+      nrf51dk_nrf51422
   bluetooth.init.test_ctlr_per_adv:
     extra_args: CONF_FILE=prj_ctlr_per_adv.conf
     platform_allow: nrf52840dk_nrf52840 nrf52dk_nrf52832
diff --git a/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf b/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf
index cfaa5fd8e1c22ca7f2b6f77d8bd7309a904c5d20..531d824c295018a99e8013a54c6e07f3ab183bea 100644
--- a/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf
+++ b/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf
@@ -11,7 +11,6 @@ CONFIG_BT_DEBUG_LOG=y
 CONFIG_LOG_BUFFER_SIZE=4096
 CONFIG_RTT_CONSOLE=y
 CONFIG_LOG_BACKEND_RTT=y
-CONFIG_LOG_MINIMAL=n
 CONFIG_LOG_BACKEND_RTT_MODE_DROP=y
 CONFIG_USE_SEGGER_RTT=y
 CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c
index d42c7e36e40a6334795f9a77347b49b00085deed..2be56223408752689cea18410b185c4e5b3a463a 100644
--- a/tests/drivers/adc/adc_api/src/test_adc.c
+++ b/tests/drivers/adc/adc_api/src/test_adc.c
@@ -163,7 +163,8 @@
 	defined(CONFIG_BOARD_STM32F103_MINI) || \
 	defined(CONFIG_BOARD_STM32_MIN_DEV_BLUE) || \
 	defined(CONFIG_BOARD_STM32_MIN_DEV_BLACK) || \
-	defined(CONFIG_BOARD_WAVESHARE_OPEN103Z)
+	defined(CONFIG_BOARD_WAVESHARE_OPEN103Z) || \
+	defined(CONFIG_BOARD_RONOTH_LODEV)
 #define ADC_DEVICE_NAME         DT_LABEL(DT_INST(0, st_stm32_adc))
 #define ADC_RESOLUTION		12
 #define ADC_GAIN		ADC_GAIN_1
diff --git a/tests/drivers/dac/dac_api/src/test_dac.c b/tests/drivers/dac/dac_api/src/test_dac.c
index ac8e445fd269c7b7e990d0f28c80b2d025ef0a8e..0da2de22d9aebf0a753f19060a786e9dd237746c 100644
--- a/tests/drivers/dac/dac_api/src/test_dac.c
+++ b/tests/drivers/dac/dac_api/src/test_dac.c
@@ -10,7 +10,9 @@
 #include <ztest.h>
 
 #if defined(CONFIG_BOARD_NUCLEO_L073RZ) || \
-	defined(CONFIG_BOARD_NUCLEO_L152RE)
+	defined(CONFIG_BOARD_NUCLEO_L152RE) || \
+	defined(CONFIG_BOARD_NUCLEO_F767ZI) || \
+	defined(CONFIG_BOARD_RONOTH_LODEV)
 
 #define DAC_DEVICE_NAME		DT_LABEL(DT_NODELABEL(dac1))
 #define DAC_CHANNEL_ID		1
diff --git a/tests/drivers/dac/dac_api/testcase.yaml b/tests/drivers/dac/dac_api/testcase.yaml
index 934ece05f4c7ff5e2fa17ade044803adbc452202..0c015ce71ab7b042947857d6529883dc120c3101 100644
--- a/tests/drivers/dac/dac_api/testcase.yaml
+++ b/tests/drivers/dac/dac_api/testcase.yaml
@@ -2,5 +2,5 @@ common:
   tags: dac drivers userspace
 tests:
   drivers.dac:
-    platform_allow: frdm_k22f frdm_k64f nucleo_l073rz nucleo_l152re twr_ke18f
+    platform_allow: frdm_k22f frdm_k64f nucleo_l073rz nucleo_l152re twr_ke18f nucleo_f767zi
     depends_on: dac
diff --git a/tests/drivers/dac/dac_loopback/src/test_dac.c b/tests/drivers/dac/dac_loopback/src/test_dac.c
index 7e0b037306c16d6cac9dbd1ad67666ac754f1233..304faf87ea54d4126452c53ba6c106392bf34250 100644
--- a/tests/drivers/dac/dac_loopback/src/test_dac.c
+++ b/tests/drivers/dac/dac_loopback/src/test_dac.c
@@ -27,7 +27,8 @@
  */
 
 #if defined(CONFIG_BOARD_NUCLEO_L073RZ) || \
-	defined(CONFIG_BOARD_NUCLEO_L152RE)
+	defined(CONFIG_BOARD_NUCLEO_L152RE) || \
+	defined(CONFIG_BOARD_RONOTH_LODEV)
 
 /*
  * DAC output on PA4 (Arduino A2 pin of Nucleo board)
diff --git a/tests/kernel/mem_protect/mem_protect/src/mem_protect.h b/tests/kernel/mem_protect/mem_protect/src/mem_protect.h
index e141ddfe1f09aea1e597885db65c7edc19f0442d..6578c2720bb8d363b7943c16684de01569e2933d 100644
--- a/tests/kernel/mem_protect/mem_protect/src/mem_protect.h
+++ b/tests/kernel/mem_protect/mem_protect/src/mem_protect.h
@@ -101,6 +101,8 @@ static inline void set_fault_valid(bool valid)
 #define MEM_REGION_ALLOC (4096)
 #elif defined(CONFIG_ARC)
 #define MEM_REGION_ALLOC (Z_ARC_MPU_ALIGN)
+#elif defined(CONFIG_ARM64)
+#define MEM_REGION_ALLOC (4096)
 #elif defined(CONFIG_ARM)
 #define MEM_REGION_ALLOC (Z_THREAD_MIN_STACK_ALIGN)
 #elif defined(CONFIG_RISCV)
diff --git a/tests/kernel/mem_protect/syscalls/src/main.c b/tests/kernel/mem_protect/syscalls/src/main.c
index c6d2cfef58aa1f40cdf2788847e3d23eb4d6651b..fa8b47d78a5df0924a4893c8f25f908979c41aa9 100644
--- a/tests/kernel/mem_protect/syscalls/src/main.c
+++ b/tests/kernel/mem_protect/syscalls/src/main.c
@@ -15,7 +15,8 @@
 #define SLEEP_MS_LONG	15000
 
 #if defined(CONFIG_BOARD_NUCLEO_F429ZI) || defined(CONFIG_BOARD_NUCLEO_F207ZG) \
-	|| defined(CONFIG_BOARD_NUCLEO_L073RZ)
+	|| defined(CONFIG_BOARD_NUCLEO_L073RZ) \
+	|| defined(CONFIG_BOARD_RONOTH_LODEV)
 #define FAULTY_ADDRESS 0x0FFFFFFF
 #elif CONFIG_MMU
 /* Just past the zephyr image mapping should be a non-present page */
diff --git a/tests/kernel/mem_protect/userspace/src/main.c b/tests/kernel/mem_protect/userspace/src/main.c
index d63f8f8b2009105c9302ea4e09fc63c51412a4a4..26486e9a7506615c8d3d16e9008a5cecce01af87 100644
--- a/tests/kernel/mem_protect/userspace/src/main.c
+++ b/tests/kernel/mem_protect/userspace/src/main.c
@@ -22,7 +22,7 @@
 #include <arch/arc/v2/mpu/arc_core_mpu.h>
 #endif
 
-#if defined(CONFIG_ARM)
+#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
 extern void arm_core_mpu_disable(void);
 #endif
 
@@ -124,6 +124,19 @@ static void test_write_control(void)
 		);
 #endif
 	zassert_unreachable("Write to control register did not fault");
+
+#elif defined(CONFIG_ARM64)
+	uint64_t val = SPSR_MODE_EL1T;
+
+	set_fault(K_ERR_CPU_EXCEPTION);
+
+	__asm__ volatile("msr spsr_el1, %0"
+			:
+			: "r" (val)
+			: "memory", "cc");
+
+	zassert_unreachable("Write to control register did not fault");
+
 #elif defined(CONFIG_ARM)
 	unsigned int msr_value;
 
@@ -183,6 +196,17 @@ static void test_disable_mmu_mpu(void)
 		"mov %eax, %cr0;\n\t"
 		);
 #endif
+#elif defined(CONFIG_ARM64)
+	uint64_t val;
+
+	set_fault(K_ERR_CPU_EXCEPTION);
+
+	__asm__ volatile("mrs %0, sctlr_el1" : "=r" (val));
+	__asm__ volatile("msr sctlr_el1, %0"
+			:
+			: "r" (val & ~(SCTLR_M_BIT | SCTLR_C_BIT))
+			: "memory", "cc");
+
 #elif defined(CONFIG_ARM)
 #ifndef CONFIG_TRUSTED_EXECUTION_NONSECURE
 	set_fault(K_ERR_CPU_EXCEPTION);
diff --git a/tests/kernel/pipe/pipe_api/src/main.c b/tests/kernel/pipe/pipe_api/src/main.c
index c7dd8afd77db671460b8aa3c83b6d89bc3956003..28d5726a63ebc32495d5174accf244e1b8341bd0 100644
--- a/tests/kernel/pipe/pipe_api/src/main.c
+++ b/tests/kernel/pipe/pipe_api/src/main.c
@@ -13,18 +13,26 @@
 
 #include <ztest.h>
 extern void test_pipe_thread2thread(void);
-
 extern void test_pipe_put_fail(void);
 extern void test_pipe_get_fail(void);
 extern void test_pipe_block_put(void);
 extern void test_pipe_block_put_sema(void);
 extern void test_pipe_get_put(void);
-extern void test_half_pipe_get_put(void);
+extern void test_pipe_get_large(void);
+
+extern void test_half_pipe_put_get(void);
 extern void test_half_pipe_saturating_block_put(void);
 extern void test_half_pipe_block_put_sema(void);
 extern void test_pipe_alloc(void);
 extern void test_pipe_reader_wait(void);
 extern void test_pipe_block_writer_wait(void);
+extern void test_pipe_cleanup(void);
+#ifdef CONFIG_USERSPACE
+extern void test_pipe_user_thread2thread(void);
+extern void test_pipe_user_put_fail(void);
+extern void test_pipe_user_get_fail(void);
+extern void test_resource_pool_auto_free(void);
+#endif
 
 extern void test_pipe_avail_r_lt_w(void);
 extern void test_pipe_avail_w_lt_r(void);
@@ -37,6 +45,20 @@ extern struct k_pipe pipe, kpipe, khalfpipe, put_get_pipe;
 extern struct k_sem end_sema;
 extern struct k_stack tstack;
 extern struct k_thread tdata;
+extern struct k_heap test_pool;
+
+#ifndef CONFIG_USERSPACE
+#define dummy_test(_name) \
+	static void _name(void) \
+	{ \
+		ztest_test_skip(); \
+	}
+
+dummy_test(test_pipe_user_thread2thread);
+dummy_test(test_pipe_user_put_fail);
+dummy_test(test_pipe_user_get_fail);
+dummy_test(test_resource_pool_auto_free);
+#endif /* !CONFIG_USERSPACE */
 
 /*test case main entry*/
 void test_main(void)
@@ -45,11 +67,21 @@ void test_main(void)
 			      &kpipe, &end_sema, &tdata, &tstack,
 			      &khalfpipe, &put_get_pipe);
 
+	k_thread_heap_assign(k_current_get(), &test_pool);
+
 	ztest_test_suite(pipe_api,
 			 ztest_1cpu_unit_test(test_pipe_thread2thread),
+			 ztest_1cpu_user_unit_test(test_pipe_user_thread2thread),
+			 ztest_1cpu_user_unit_test(test_pipe_user_put_fail),
+			 ztest_user_unit_test(test_pipe_user_get_fail),
+			 ztest_unit_test(test_resource_pool_auto_free),
 			 ztest_1cpu_unit_test(test_pipe_put_fail),
 			 ztest_unit_test(test_pipe_get_fail),
-			 ztest_unit_test(test_half_pipe_get_put),
+			 ztest_unit_test(test_half_pipe_put_get),
+			 ztest_unit_test(test_pipe_get_put),
+			 ztest_unit_test(test_pipe_get_large),
+			 ztest_1cpu_unit_test(test_pipe_alloc),
+			 ztest_unit_test(test_pipe_cleanup),
 			 ztest_unit_test(test_pipe_reader_wait),
 			 ztest_unit_test(test_pipe_avail_r_lt_w),
 			 ztest_unit_test(test_pipe_avail_w_lt_r),
diff --git a/tests/kernel/pipe/pipe_api/src/test_pipe_avail.c b/tests/kernel/pipe/pipe_api/src/test_pipe_avail.c
index 89c894174e0c0e6a80dc4abeebc8c1b9352cd6b7..46749136d7e8bcfb0432ec50df36754133bbb30c 100644
--- a/tests/kernel/pipe/pipe_api/src/test_pipe_avail.c
+++ b/tests/kernel/pipe/pipe_api/src/test_pipe_avail.c
@@ -20,11 +20,16 @@ static struct k_pipe pipe = {
 
 static struct k_pipe bufferless;
 
+static struct k_pipe bufferless1 = {
+	.buffer = data,
+	.size = 0,
+};
+
 /**
- * @brief Ensure that bufferless pipes return 0 bytes available
+ * @brief Pipes with no buffer or size 0 should return 0 bytes available
  *
  * Pipes can be created to be bufferless (i.e. @ref k_pipe.buffer is `NULL`
- * and @ref k_pipe.size is 0).
+ * or @ref k_pipe.size is 0).
  *
  * If either of those conditions is true, then @ref k_pipe_read_avail and
  * @ref k_pipe_write_avail should return 0.
@@ -45,6 +50,12 @@ void test_pipe_avail_no_buffer(void)
 
 	w_avail = k_pipe_write_avail(&bufferless);
 	zassert_equal(w_avail, 0, "write: expected: 0 actual: %u", w_avail);
+
+	r_avail = k_pipe_read_avail(&bufferless1);
+	zassert_equal(r_avail, 0, "read: expected: 0 actual: %u", r_avail);
+
+	w_avail = k_pipe_write_avail(&bufferless1);
+	zassert_equal(w_avail, 0, "write: expected: 0 actual: %u", w_avail);
 }
 
 /**
diff --git a/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c b/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c
index 7300d56d47515c14aeeeb2a65538b82fb3cd63da..bfae22fc251dce411be186bc26417f6cc02f7348 100644
--- a/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c
+++ b/tests/kernel/pipe/pipe_api/src/test_pipe_contexts.c
@@ -11,6 +11,8 @@
 #define BYTES_TO_WRITE	16
 #define BYTES_TO_READ BYTES_TO_WRITE
 
+K_HEAP_DEFINE(mpool, PIPE_LEN * 1);
+
 static ZTEST_DMEM unsigned char __aligned(4) data[] =
 "abcd1234$%^&PIPEefgh5678!/?*EPIPijkl9012[]<>PEPImnop3456{}()IPEP";
 BUILD_ASSERT(sizeof(data) >= PIPE_LEN);
@@ -20,7 +22,8 @@ K_PIPE_DEFINE(kpipe, PIPE_LEN, 4);
 K_PIPE_DEFINE(khalfpipe, (PIPE_LEN / 2), 4);
 K_PIPE_DEFINE(kpipe1, PIPE_LEN, 4);
 K_PIPE_DEFINE(pipe_test_alloc, PIPE_LEN, 4);
-struct k_pipe pipe;
+K_PIPE_DEFINE(ksmallpipe, 10, 2);
+struct k_pipe pipe, pipe1;
 
 K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
 K_THREAD_STACK_DEFINE(tstack1, STACK_SIZE);
@@ -30,6 +33,17 @@ struct k_thread tdata1;
 struct k_thread tdata2;
 K_SEM_DEFINE(end_sema, 0, 1);
 
+#ifdef CONFIG_64BIT
+#define SZ 256
+#else
+#define SZ 128
+#endif
+K_HEAP_DEFINE(test_pool, SZ * 4);
+
+struct mem_block {
+	void *data;
+};
+
 static void tpipe_put(struct k_pipe *ppipe, k_timeout_t timeout)
 {
 	size_t to_wt, wt_byte = 0;
@@ -90,6 +104,23 @@ static void tpipe_thread_thread(struct k_pipe *ppipe)
 	k_thread_abort(tid);
 }
 
+static void tpipe_kthread_to_kthread(struct k_pipe *ppipe)
+{
+	/**TESTPOINT: thread-thread data passing via pipe*/
+	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
+				      tThread_entry, ppipe, NULL, NULL,
+				      K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
+
+	tpipe_put(ppipe, K_NO_WAIT);
+	k_sem_take(&end_sema, K_FOREVER);
+
+	k_sem_take(&end_sema, K_FOREVER);
+	tpipe_get(ppipe, K_FOREVER);
+
+	/* clear the spawned thread avoid side effect */
+	k_thread_abort(tid);
+}
+
 static void tpipe_put_no_wait(struct k_pipe *ppipe)
 {
 	size_t to_wt, wt_byte = 0;
@@ -104,6 +135,103 @@ static void tpipe_put_no_wait(struct k_pipe *ppipe)
 	}
 }
 
+static void tpipe_put_small_size(struct k_pipe *ppipe, k_timeout_t timeout)
+{
+	size_t to_wt, wt_byte = 0;
+
+	for (int i = 0; i < PIPE_LEN; i += wt_byte) {
+		/**TESTPOINT: pipe put*/
+		to_wt = 15;
+		k_pipe_put(ppipe, &data[i], to_wt, &wt_byte, 1, timeout);
+	}
+}
+
+static void tpipe_get_small_size(struct k_pipe *ppipe, k_timeout_t timeout)
+{
+	unsigned char rx_data[PIPE_LEN];
+	size_t to_rd, rd_byte = 0;
+
+	/*get pipe data from "pipe_put"*/
+	for (int i = 0; i < PIPE_LEN; i += rd_byte) {
+		/**TESTPOINT: pipe get*/
+		to_rd = 15;
+		zassert_false(k_pipe_get(ppipe, &rx_data[i], to_rd,
+					 &rd_byte, 1, timeout), NULL);
+	}
+}
+
+
+static void tpipe_get_large_size(struct k_pipe *ppipe, k_timeout_t timeout)
+{
+	unsigned char rx_data[PIPE_LEN];
+	size_t to_rd, rd_byte = 0;
+
+	/*get pipe data from "pipe_put"*/
+	for (int i = 0; i < PIPE_LEN; i += rd_byte) {
+		/**TESTPOINT: pipe get*/
+		to_rd = (PIPE_LEN - i) >= 128 ?
+			128 : (PIPE_LEN - i);
+		zassert_false(k_pipe_get(ppipe, &rx_data[i], to_rd,
+					 &rd_byte, 1, timeout), NULL);
+	}
+}
+
+
+/**
+ * @brief Test Initialization and buffer allocation of pipe,
+ * with various parameters
+ * @see k_pipe_alloc_init(), k_pipe_cleanup()
+ */
+void test_pipe_alloc(void)
+{
+	int ret;
+
+	zassert_false(k_pipe_alloc_init(&pipe_test_alloc, PIPE_LEN), NULL);
+
+	tpipe_kthread_to_kthread(&pipe_test_alloc);
+	k_pipe_cleanup(&pipe_test_alloc);
+
+	zassert_false(k_pipe_alloc_init(&pipe_test_alloc, 0), NULL);
+	k_pipe_cleanup(&pipe_test_alloc);
+
+	ret = k_pipe_alloc_init(&pipe_test_alloc, 2048);
+	zassert_true(ret == -ENOMEM,
+		"resource pool max block size is not smaller then requested buffer");
+}
+
+static void thread_for_get_forever(void *p1, void *p2, void *p3)
+{
+	tpipe_get((struct k_pipe *)p1, K_FOREVER);
+}
+
+void test_pipe_cleanup(void)
+{
+	int ret;
+
+	zassert_false(k_pipe_alloc_init(&pipe_test_alloc, PIPE_LEN), NULL);
+
+	/**TESTPOINT: test if a dynamically allocated buffer can be freed*/
+	ret = k_pipe_cleanup(&pipe_test_alloc);
+	zassert_true((ret == 0) && (pipe_test_alloc.buffer == NULL),
+			"Failed to free buffer with k_pipe_cleanup().");
+
+	/**TESTPOINT: nothing to do with k_pipe_cleanup() for static buffer in pipe*/
+	ret = k_pipe_cleanup(&kpipe);
+	zassert_true((ret == 0) && (kpipe.buffer != NULL),
+			"Static buffer should not be freed.");
+
+	zassert_false(k_pipe_alloc_init(&pipe_test_alloc, PIPE_LEN), NULL);
+
+	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
+			thread_for_get_forever, &pipe_test_alloc, NULL,
+			NULL, K_PRIO_PREEMPT(0), 0, K_NO_WAIT);
+	k_sleep(K_MSEC(100));
+
+	ret = k_pipe_cleanup(&pipe_test_alloc);
+	zassert_true(ret == -EAGAIN, "k_pipe_cleanup() should not return with 0.");
+	k_thread_abort(tid);
+}
+
 static void thread_handler(void *p1, void *p2, void *p3)
 {
 	tpipe_put_no_wait((struct k_pipe *)p1);
@@ -162,7 +290,6 @@ static void thread_handler(void *p1, void *p2, void *p3)
 void test_pipe_thread2thread(void)
 {
 	/**TESTPOINT: test k_pipe_init pipe*/
-
 	k_pipe_init(&pipe, data, PIPE_LEN);
 	tpipe_thread_thread(&pipe);
 
@@ -189,29 +316,119 @@ void test_pipe_user_thread2thread(void)
 }
 #endif
 
+/**
+ * @brief Test resource pool free
+ * @see k_heap_alloc()
+ */
+#ifdef CONFIG_USERSPACE
+void test_resource_pool_auto_free(void)
+{
+	/* Pool has 2 blocks, both should succeed if kernel object and pipe
+	 * buffer are auto-freed when the allocating threads exit
+	 */
+	zassert_true(k_heap_alloc(&test_pool, 64, K_NO_WAIT) != NULL, NULL);
+	zassert_true(k_heap_alloc(&test_pool, 64, K_NO_WAIT) != NULL, NULL);
+}
+#endif
+
 static void tThread_half_pipe_put(void *p1, void *p2, void *p3)
 {
 	tpipe_put((struct k_pipe *)p1, K_FOREVER);
 }
 
+static void tThread_half_pipe_get(void *p1, void *p2, void *p3)
+{
+	tpipe_get((struct k_pipe *)p1, K_FOREVER);
+}
+
 /**
- * @brief Test get/put with smaller pipe buffer
+ * @brief Test put/get with smaller pipe buffer
  * @see k_pipe_put(), k_pipe_get()
  */
-void test_half_pipe_get_put(void)
+void test_half_pipe_put_get(void)
 {
+	unsigned char rx_data[PIPE_LEN];
+	size_t rd_byte = 0;
+	int ret;
+
+	/* TESTPOINT: min_xfer > bytes_to_read */
+	ret = k_pipe_put(&kpipe, &rx_data[0], 1, &rd_byte, 24, K_NO_WAIT);
+	zassert_true(ret == -EINVAL, NULL);
+	ret = k_pipe_put(&kpipe, &rx_data[0], 24, NULL, 1, K_NO_WAIT);
+	zassert_true(ret == -EINVAL, NULL);
+
 	/**TESTPOINT: thread-thread data passing via pipe*/
-	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
+	k_tid_t tid1 = k_thread_create(&tdata1, tstack1, STACK_SIZE,
+				      tThread_half_pipe_get, &khalfpipe,
+				      NULL, NULL, K_PRIO_PREEMPT(0),
+				      K_INHERIT_PERMS | K_USER, K_NO_WAIT);
+
+	k_tid_t tid2 = k_thread_create(&tdata2, tstack2, STACK_SIZE,
+				      tThread_half_pipe_get, &khalfpipe,
+				      NULL, NULL, K_PRIO_PREEMPT(0),
+				      K_INHERIT_PERMS | K_USER, K_NO_WAIT);
+
+	k_sleep(K_MSEC(100));
+	tpipe_put_small_size(&khalfpipe, K_NO_WAIT);
+
+	/* clear the spawned thread avoid side effect */
+	k_thread_abort(tid1);
+	k_thread_abort(tid2);
+}
+
+void test_pipe_get_put(void)
+{
+	unsigned char rx_data[PIPE_LEN];
+	size_t rd_byte = 0;
+	int ret;
+
+	/* TESTPOINT: min_xfer > bytes_to_read */
+	ret = k_pipe_get(&kpipe, &rx_data[0], 1, &rd_byte, 24, K_NO_WAIT);
+	zassert_true(ret == -EINVAL, NULL);
+	ret = k_pipe_get(&kpipe, &rx_data[0], 24, NULL, 1, K_NO_WAIT);
+	zassert_true(ret == -EINVAL, NULL);
+
+	/**TESTPOINT: thread-thread data passing via pipe*/
+	k_tid_t tid1 = k_thread_create(&tdata1, tstack1, STACK_SIZE,
+				      tThread_half_pipe_put, &khalfpipe,
+				      NULL, NULL, K_PRIO_PREEMPT(0),
+				      K_INHERIT_PERMS | K_USER, K_NO_WAIT);
+
+	k_tid_t tid2 = k_thread_create(&tdata2, tstack2, STACK_SIZE,
 				      tThread_half_pipe_put, &khalfpipe,
 				      NULL, NULL, K_PRIO_PREEMPT(0),
 				      K_INHERIT_PERMS | K_USER, K_NO_WAIT);
 
-	tpipe_get(&khalfpipe, K_FOREVER);
+	k_sleep(K_MSEC(100));
+	tpipe_get_small_size(&khalfpipe, K_NO_WAIT);
 
 	/* clear the spawned thread avoid side effect */
-	k_thread_abort(tid);
+	k_thread_abort(tid1);
+	k_thread_abort(tid2);
+}
+
+void test_pipe_get_large(void)
+{
+	/**TESTPOINT: thread-thread data passing via pipe*/
+	k_tid_t tid1 = k_thread_create(&tdata1, tstack1, STACK_SIZE,
+				      tThread_half_pipe_put, &khalfpipe,
+				      NULL, NULL, K_PRIO_PREEMPT(0),
+				      K_INHERIT_PERMS | K_USER, K_NO_WAIT);
+
+	k_tid_t tid2 = k_thread_create(&tdata2, tstack2, STACK_SIZE,
+				      tThread_half_pipe_put, &khalfpipe,
+				      NULL, NULL, K_PRIO_PREEMPT(0),
+				      K_INHERIT_PERMS | K_USER, K_NO_WAIT);
+
+	k_sleep(K_MSEC(100));
+	tpipe_get_large_size(&khalfpipe, K_NO_WAIT);
+
+	/* clear the spawned thread avoid side effect */
+	k_thread_abort(tid1);
+	k_thread_abort(tid2);
 }
 
+
 /**
  * @brief Test pending reader in pipe
  * @see k_pipe_put(), k_pipe_get()
diff --git a/tests/kernel/threads/dynamic_thread/prj.conf b/tests/kernel/threads/dynamic_thread/prj.conf
index 804af8ea9a8893548026c63c7060b277d7eba5cb..59a2fa2c3e2b4574a2d5442f3f2a40cdcbe92197 100644
--- a/tests/kernel/threads/dynamic_thread/prj.conf
+++ b/tests/kernel/threads/dynamic_thread/prj.conf
@@ -1,3 +1,3 @@
 CONFIG_ZTEST=y
 CONFIG_TEST_USERSPACE=y
-CONFIG_HEAP_MEM_POOL_SIZE=4096
+CONFIG_HEAP_MEM_POOL_SIZE=8192
diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c
index 25d1b1effcd451882b2df02425475fad1684a7c4..43fb376b68be18196f6caf9f2876630834274da2 100644
--- a/tests/lib/devicetree/api/src/main.c
+++ b/tests/lib/devicetree/api/src/main.c
@@ -15,6 +15,8 @@
  * - DT_IO_CHANNELS_LABEL_BY_IDX
  * - DT_IO_CHANNELS_LABEL_BY_NAME
  * - DT_IO_CHANNELS_LABEL
+ * - DT_DMAS_LABEL_BY_IDX
+ * - DT_DMAS_LABEL_BY_NAME
  * - DT_INST_CLOCKS_LABEL_BY_IDX
  * - DT_INST_CLOCKS_LABEL_BY_NAME
  * - DT_INST_CLOCKS_LABEL
@@ -24,6 +26,8 @@
  * - DT_INST_IO_CHANNELS_LABEL_BY_IDX
  * - DT_INST_IO_CHANNELS_LABEL_BY_NAME
  * - DT_INST_IO_CHANNELS_LABEL
+ * - DT_INST_DMAS_LABEL_BY_IDX
+ * - DT_INST_DMAS_LABEL_BY_NAME
  */
 #define __DEPRECATED_MACRO
 
diff --git a/tests/subsys/debug/coredump/prj.conf b/tests/subsys/debug/coredump/prj.conf
index ef877888911fdda3fdecc58fd3814b4f65585654..5436a6c2617c816eac33282fdffcdd1116fe3552 100644
--- a/tests/subsys/debug/coredump/prj.conf
+++ b/tests/subsys/debug/coredump/prj.conf
@@ -1,5 +1,4 @@
-CONFIG_LOG=y
-CONFIG_LOG_MODE_MINIMAL=y
+CONFIG_TEST=y
 CONFIG_DEBUG_COREDUMP=y
 CONFIG_DEBUG_COREDUMP_BACKEND_LOGGING=y
 CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y
diff --git a/tests/unit/rbtree/main.c b/tests/unit/rbtree/main.c
index 7c730a66fb3c587439e7294f049bbbb890abe346..c07fd3c2495214237210f732b63ccc373afc1946 100644
--- a/tests/unit/rbtree/main.c
+++ b/tests/unit/rbtree/main.c
@@ -245,9 +245,43 @@ void test_rbtree_spam(void)
 	} while (size < MAX_NODES);
 }
 
+/**
+ * @brief Test removing a node with abnormal color.
+ *
+ * @details Initialize a tree and insert it,
+ * and test APIs rb_get_min(), rb_get_max().
+ *
+ * @ingroup lib_rbtree_tests
+ *
+ * @see rb_get_min(), rb_get_max()
+ */
+void test_rb_get_minmax(void)
+{
+	struct rbnode temp = {0};
+
+	/* Initialize a tree and insert it */
+	(void)memset(&tree, 0, sizeof(tree));
+	tree.lessthan_fn = node_lessthan;
+	(void)memset(nodes, 0, sizeof(nodes));
+
+	zassert_true(rb_get_min(&tree) == NULL, "the tree is invalid");
+
+	for (int i = 0; i < 8; i++) {
+		rb_insert(&tree, &nodes[i]);
+	}
+
+	rb_remove(&tree, &temp);
+
+	/* Check if tree's max and min node are expected */
+	zassert_true(rb_get_min(&tree) == &nodes[0], "the tree is invalid");
+	zassert_true(rb_get_max(&tree) == &nodes[7], "the tree is invalid");
+}
+
 void test_main(void)
 {
 	ztest_test_suite(test_rbtree,
-			 ztest_unit_test(test_rbtree_spam));
+			 ztest_unit_test(test_rbtree_spam),
+			 ztest_unit_test(test_rb_get_minmax)
+			 );
 	ztest_run_test_suite(test_rbtree);
 }
diff --git a/tests/ztest/error_hook/README.txt b/tests/ztest/error_hook/README.txt
index 0f0a0b4e877e8a1ce1a9460c147fdd246646784a..c4e97b04e1e6bf6328a44d9698d6076c7c9e94ce 100644
--- a/tests/ztest/error_hook/README.txt
+++ b/tests/ztest/error_hook/README.txt
@@ -2,9 +2,9 @@ Title: A common fatal error and assert fail handler
 
 Description:
 
-These two common handler is in order to reduce the redundancy code writing
-for fatal and assert handler for error case testing. They can be used both
-in kernel and userspace, and are also SMP safe.
+These two common handlers are developed in order to reduce the redundancy
+code writing for fatal and assert handler for error case testing. They can
+be used both in kernel and userspace, and they are also SMP safe.
 
 
 Why doing this
@@ -12,13 +12,14 @@ Why doing this
 
 When writing error testing case (or we call it negative test case), we might
 have to write self-defined k_sys_fatal_handler or post_assert_handler to deal
-with the errors we caught, in order to make test going on. This mean much
-identical code would be written. So we try to make it as a common part and
-let other test case or app can reuse it.
+with the errors we caught, in order to make the test continue. This means much
+identical code would be written. So we try to move the error handler definition
+into a common part and let other test suites or applications reuse it, instead
+of defining their own.
 
-And when error happened, it sometimes need a special action to make our testing
-program back to normal, such as release some resource hold before error
-happened. This is why we add a hook on it, in order to achieve that goal.
+And when error happens, we sometimes need a special action to make our testing
+program return back to normal, such as releasing some resource hold before the
+error happened. This is why we add a hook on it, in order to achieve that goal.
 
 
 How to use it in you app
@@ -48,8 +49,8 @@ Step4: call ztest_set_assert_valid(true) before where your target function
        call.
 
 
-You can choose to use one or both of them, depneds on your need.
-If you use none of them, you can still defined your own fatal or assert handler
+You can choose to use one or both of them, depending on your needs.
+If you use none of them, you can still define your own fatal or assert handler
 as usual.
 
 
@@ -57,19 +58,21 @@ Test example in this test set
 =============================
 
 This test verifies if the common fatal error and assert fail handler works.
-If the expected error got caught, the test case pass.
+If the expected error was caught, the test case will pass.
 
 test_catch_assert_fail
   - To call a function then giving the condition to trigger the assert fail,
     then catch it by the assert handler.
 
 test_catch_fatal_error
-  - start a thread to test trigger a null address then catch fatal error.
-  - start a thread to test trigger a illegal instruction then catch fatal
-    error.
-  - start a thread to test trigger a divide zero error then catch fatal error.
-  - start a thread to call k_oops() then catch fatal error.
-  - start a thread to call k_panel() then catch fatal error.
+  - start a thread to test triggerring a null address dereferencing, then catch
+    the (expected) fatal error.
+  - start a thread to test triggerring an illegal instruction, then catch
+    the (expected) fatal error.
+  - start a thread to test triggerring a divide-by-zero error, then catch
+    the (expected) fatal error.
+  - start a thread to call k_oops() then catch the (expected) fatal error.
+  - start a thread to call k_panel() then catch the (expected) fatal error.
 
 test_catch_assert_in_isr
   - start a thread to enter ISR context by calling irq_offload(), then trigger
@@ -77,14 +80,14 @@ test_catch_assert_in_isr
 
 test_catch_z_oops
   - Pass illegal address by syscall, then inside the syscall handler, the
-    Z_OOPS macro will trigger a fatal error then got caught.
+    Z_OOPS macro will trigger a fatal error that will get caught (as expected).
 
 
 
 Limitation of this usage
 ========================
 
-Trigger an fatal error in ISR context, that will cause problem due to
+Trigger a fatal error in ISR context, that will cause problem due to
 the interrupt stack is already abnormal when we want to continue other
 test case, we do not recover it so far.
 
@@ -176,20 +179,15 @@ Assert error expected as part of test case.
  PASS - test_catch_assert_in_isr
 ===================================================================
 START - test_catch_z_oops
-E: Page fault at address (nil) (error code 0x4)
-E: Linear address not present in page tables
-E: Access violation: user thread not allowed to read
-E: PTE: not present
-E: EAX: 0x00000000, EBX: 0x0011303c, ECX: 0x00000000, EDX: 0x0011303c
-E: ESI: 0x00000000, EDI: 0x00130fe8, EBP: 0x00130fc0, ESP: 0x00130fc0
-E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0
+E: EAX: 0x00000000, EBX: 0x00000000, ECX: 0x00000000, EDX: 0x00000000
+E: ESI: 0x00000000, EDI: 0x00000000, EBP: 0x00000000, ESP: 0x00000000
+E: EFLAGS: 0x001003c4 CS: 0x0511 CR3: 0x00115740
 E: call trace:
-E: EIP: 0x00100544
-E:      0x00104808 (0x130033)
-E:      0x001010ea (0x11303c)
-E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
-E: Current thread: 0x1140a0 (unknown)
-Caught system error -- reason 0 1
+E: EIP: 0x0010ff9e
+E: NULL base ptr
+E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0
+E: Current thread: 0x114120 (unknown)
+Caught system error -- reason 3 1
 Fatal error expected as part of test case.
  PASS - test_catch_z_oops
 ===================================================================
diff --git a/tests/ztest/error_hook/src/main.c b/tests/ztest/error_hook/src/main.c
index 6ef1ea13eaf3bae55dd5b8974b7fbfa7f1d59536..b8a190a13b189bed9c39f06da9d6060a0312cf5e 100644
--- a/tests/ztest/error_hook/src/main.c
+++ b/tests/ztest/error_hook/src/main.c
@@ -41,11 +41,11 @@ static void trigger_assert_fail(void *a)
 	__ASSERT(a != NULL, "parameter a should not be NULL!");
 }
 
-static void trigger_fault_illeagl_instuction(void)
+static void trigger_fault_illegal_instruction(void)
 {
 	void *a = NULL;
 
-	/* execute an illeagal instructions */
+	/* execute an illeagal instruction */
 	((void(*)(void))&a)();
 }
 
@@ -70,7 +70,7 @@ static void trigger_fault_access(void)
 	 */
 	void *a = (void *)NULL;
 #endif
-	/* access a illeagal address */
+	/* access an illegal address */
 	volatile int b = *((int *)a);
 
 	printk("b is %d\n", b);
@@ -81,7 +81,7 @@ static void trigger_fault_divide_zero(void)
 	int a = 1;
 	int b = 0;
 
-	/* divde zero */
+	/* divide by zero */
 	a = a / b;
 	printk("a is %d\n", a);
 }
@@ -98,15 +98,16 @@ static void trigger_fault_panic(void)
 
 static void release_offload_sem(void)
 {
-	/* Semaphore used inside irq_offload need to be
-	 * released after assert or fault happened.
+	/* Semaphore used inside irq_offload needs to be
+	 * released after an assert or a fault has happened.
 	 */
 	k_sem_give(&offload_sem);
 }
 
-/* This is the fatal error hook that allow you to do actions after
- * fatal error happened. This is optional, you can choose to define
- * this yourself. If not, it will use the default one.
+/* This is the fatal error hook that allows you to do actions after
+ * the fatal error has occurred. This is optional; you can choose
+ * to define the hook yourself. If not, the program will use the
+ * default one.
  */
 void ztest_post_fatal_error_hook(unsigned int reason,
 		const z_arch_esf_t *pEsf)
@@ -134,9 +135,9 @@ void ztest_post_fatal_error_hook(unsigned int reason,
 	}
 }
 
-/* This is the assert fail post hook that allow you to do actions after
- * assert fail happened. This is optional, you can choose to define
- * this yourself. If not, it will use the default one.
+/* This is the assert fail post hook that allows you to do actions after
+ * the assert fail happened. This is optional, you can choose to define
+ * the hook yourself. If not, the program will use the default one.
  */
 void ztest_post_assert_fail_hook(void)
 {
@@ -170,7 +171,7 @@ static void tThread_entry(void *p1, void *p2, void *p3)
 		break;
 	case ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION:
 		ztest_set_fault_valid(true);
-		trigger_fault_illeagl_instuction();
+		trigger_fault_illegal_instruction();
 		break;
 	case ZTEST_CATCH_FATAL_DIVIDE_ZERO:
 		ztest_set_fault_valid(true);
@@ -274,9 +275,12 @@ void test_catch_assert_in_isr(void)
 
 
 #if defined(CONFIG_USERSPACE)
-static void trigger_z_oops(void *a)
+static void trigger_z_oops(void)
 {
-	Z_OOPS(*((bool *)a));
+	/* Set up a dummy syscall frame, pointing to a valid area in memory. */
+	_current->syscall_frame = _image_ram_start;
+
+	Z_OOPS(true);
 }
 
 /**
@@ -292,7 +296,7 @@ void test_catch_z_oops(void)
 	case_type = ZTEST_CATCH_USER_FATAL_Z_OOPS;
 
 	ztest_set_fault_valid(true);
-	trigger_z_oops((void *)false);
+	trigger_z_oops();
 }
 #endif
 
@@ -307,7 +311,7 @@ void test_main(void)
 			 ztest_user_unit_test(test_catch_assert_fail),
 			 ztest_user_unit_test(test_catch_fatal_error),
 			 ztest_unit_test(test_catch_assert_in_isr),
-			 ztest_user_unit_test(test_catch_z_oops)
+			 ztest_unit_test(test_catch_z_oops)
 			 );
 	ztest_run_test_suite(error_hook_tests);
 #else
diff --git a/west.yml b/west.yml
index bba84dc8e356af0a654ea74b889d2ecaadf76356..ab75ee80abf709b5302edcffbd10f4b199e7bc29 100644
--- a/west.yml
+++ b/west.yml
@@ -54,7 +54,7 @@ manifest:
       revision: f1fa8241f8786198ba41155413243de36ed878a5
       path: modules/hal/infineon
     - name: hal_nordic
-      revision: 46b65a5a6ebb6d089431bc80a4f78746c1c90a88
+      revision: 6667950c239bc6ecb8a8bcb737c41ec98681c485
       path: modules/hal/nordic
     - name: hal_openisa
       revision: 40d049f69c50b58ea20473bee14cf93f518bf262
@@ -66,7 +66,7 @@ manifest:
       revision: a1ec761014740a08699720298dd37ad4da360840
       path: modules/hal/microchip
     - name: hal_silabs
-      revision: de93f34488f2ab4d6337af0819b377636034fcda
+      revision: be39d4eebeddac6e18e9c0c3ba1b31ad1e82eaed
       path: modules/hal/silabs
     - name: hal_st
       revision: b52fdbf4b62439be9fab9bb4bae9690a42d2fb14