Merge "feat(spm_mm): move mm_communication header define to general header" into integration
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 4c610ad..46e5f67 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -2,17 +2,19 @@
 updates:
   - target-branch: "main"
     package-ecosystem: "npm"
-    directories: ["/"]
+    versioning-strategy: "lockfile-only"
+    directories: ["/", "/tools/conventional-changelog-tf-a"]
     schedule:
       interval: "daily"
     groups:
       dev-deps:
         patterns: ["*"]
-        update-types: ["major", "minor", "patch"]
+        update-types: ["minor", "patch"]
 
   - target-branch: "lts-v2.10"
     package-ecosystem: "npm"
-    directories: ["/"]
+    versioning-strategy: "lockfile-only"
+    directories: ["/", "/tools/conventional-changelog-tf-a"]
     schedule:
       interval: "daily"
     groups:
@@ -22,7 +24,8 @@
 
   - target-branch: "lts-v2.8"
     package-ecosystem: "npm"
-    directories: ["/"]
+    versioning-strategy: "lockfile-only"
+    directories: ["/", "/tools/conventional-changelog-tf-a"]
     schedule:
       interval: "daily"
     groups:
@@ -32,16 +35,18 @@
 
   - target-branch: "main"
     package-ecosystem: "pip"
-    directories: ["/", "/tools/cot_dt2c", "/tools/tlc"]
+    versioning-strategy: "lockfile-only"
+    directories: ["/", "/tools/cot_dt2c", "/tools/memory", "/tools/tlc"]
     schedule:
       interval: "daily"
     groups:
       dev-deps:
         patterns: ["*"]
-        update-types: ["major", "minor", "patch"]
+        update-types: ["minor", "patch"]
 
   - target-branch: "lts-v2.10"
     package-ecosystem: "pip"
+    versioning-strategy: "lockfile-only"
     directories: ["/"]
     schedule:
       interval: "daily"
@@ -52,6 +57,7 @@
 
   - target-branch: "lts-v2.8"
     package-ecosystem: "pip"
+    versioning-strategy: "lockfile-only"
     directories: ["/"]
     schedule:
       interval: "daily"
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 2d1afab..d308fdd 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,4 +1,4 @@
-# Copyright (c) 2023-2024, Arm Limited. All rights reserved
+# Copyright (c) 2023-2025, Arm Limited. All rights reserved
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -20,7 +20,7 @@
     post_create_environment:
       - pip install poetry=="1.3.2"
     post_install:
-      - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs
+      - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --no-root --with docs
 
 sphinx:
   configuration: docs/conf.py
@@ -28,4 +28,3 @@
 # Auxiliary formats to export to (in addition to the default HTML output).
 formats:
   - pdf
-
diff --git a/Makefile b/Makefile
index 28ff849..4cba2b0 100644
--- a/Makefile
+++ b/Makefile
@@ -433,28 +433,12 @@
 ################################################################################
 
 ifneq (${SPD},none)
-	ifeq (${ARCH},aarch32)
-                $(error "Error: SPD is incompatible with AArch32.")
-	endif
-
-	ifdef EL3_PAYLOAD_BASE
-                $(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.")
-                $(warning "The SPD and its BL32 companion will be present but \
-                ignored.")
-	endif
-
 	ifeq (${SPD},spmd)
 	# SPMD is located in std_svc directory
 		SPD_DIR := std_svc
 
 		ifeq ($(SPMD_SPM_AT_SEL2),1)
 			CTX_INCLUDE_EL2_REGS := 1
-			ifeq ($(SPMC_AT_EL3),1)
-                                $(error SPM cannot be enabled in both S-EL2 and EL3.)
-			endif
-			ifeq ($(CTX_INCLUDE_SVE_REGS),1)
-                                $(error SVE context management not needed with Hafnium SPMC.)
-			endif
 		endif
 
 		ifeq ($(findstring optee_sp,$(ARM_SPMC_MANIFEST_DTS)),optee_sp)
@@ -476,12 +460,6 @@
 		ifneq ($(SP_LAYOUT_FILE),)
 		BL2_ENABLE_SP_LOAD := 1
 		endif
-
-		ifeq ($(SPMC_AT_EL3_SEL0_SP),1)
-			ifneq ($(SPMC_AT_EL3),1)
-			$(error SEL0 SP cannot be enabled without SPMC at EL3)
-			endif
-		endif
 	else
 		# All other SPDs in spd directory
 		SPD_DIR := spd
@@ -507,15 +485,6 @@
 	# over the sources.
 endif #(SPD=none)
 
-ifeq (${ENABLE_SPMD_LP}, 1)
-ifneq (${SPD},spmd)
-        $(error Error: ENABLE_SPMD_LP requires SPD=spmd.)
-endif
-ifeq ($(SPMC_AT_EL3),1)
-        $(error SPMC at EL3 not supported when enabling SPMD Logical partitions.)
-endif
-endif
-
 ################################################################################
 # Include the platform specific Makefile after the SPD Makefile (the platform
 # makefile may use all previous definitions in this file)
@@ -774,6 +743,42 @@
 # Check incompatible options and dependencies
 ################################################################################
 
+# Handle all invalid build configurations with SPMD usage.
+ifeq (${ENABLE_SPMD_LP}, 1)
+ifneq (${SPD},spmd)
+	$(error Error: ENABLE_SPMD_LP requires SPD=spmd.)
+endif
+ifeq ($(SPMC_AT_EL3),1)
+	$(error SPMC at EL3 not supported when enabling SPMD Logical partitions.)
+endif
+endif
+
+ifneq (${SPD},none)
+ifeq (${ARCH},aarch32)
+	$(error "Error: SPD is incompatible with AArch32.")
+endif
+ifdef EL3_PAYLOAD_BASE
+	$(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.")
+	$(warning "The SPD and its BL32 companion will be present but ignored.")
+endif
+ifeq (${SPD},spmd)
+ifeq ($(SPMD_SPM_AT_SEL2),1)
+	ifeq ($(SPMC_AT_EL3),1)
+		$(error SPM cannot be enabled in both S-EL2 and EL3.)
+	endif
+	ifeq ($(CTX_INCLUDE_SVE_REGS),1)
+		$(error SVE context management not needed with Hafnium SPMC.)
+	endif
+endif
+
+ifeq ($(SPMC_AT_EL3_SEL0_SP),1)
+	ifneq ($(SPMC_AT_EL3),1)
+		$(error SEL0 SP cannot be enabled without SPMC at EL3)
+	endif
+endif
+endif #(SPD=spmd)
+endif #(SPD!=none)
+
 # USE_DEBUGFS experimental feature recommended only in debug builds
 ifeq (${USE_DEBUGFS},1)
         ifeq (${DEBUG},1)
@@ -1185,7 +1190,6 @@
 	DYN_DISABLE_AUTH \
 	EL3_EXCEPTION_HANDLING \
 	ENABLE_AMU_AUXILIARY_COUNTERS \
-	ENABLE_AMU_FCONF \
 	AMU_RESTRICT_COUNTERS \
 	ENABLE_ASSERTIONS \
 	ENABLE_PIE \
@@ -1244,13 +1248,14 @@
 	ENCRYPT_BL31 \
 	ENCRYPT_BL32 \
 	ERRATA_SPECULATIVE_AT \
+	ERRATA_SME_POWER_DOWN \
 	RAS_TRAP_NS_ERR_REC_ACCESS \
 	COT_DESC_IN_DTB \
 	USE_SP804_TIMER \
 	PSA_FWU_SUPPORT \
 	PSA_FWU_METADATA_FW_STORE_DESC \
 	ENABLE_MPMM \
-	ENABLE_MPMM_FCONF \
+	FEAT_PABANDON \
 	FEATURE_DETECTION \
 	TRNG_SUPPORT \
 	ENABLE_ERRATA_ALL \
@@ -1359,7 +1364,6 @@
 	DISABLE_MTPMU \
 	ENABLE_FEAT_AMU \
 	ENABLE_AMU_AUXILIARY_COUNTERS \
-	ENABLE_AMU_FCONF \
 	AMU_RESTRICT_COUNTERS \
 	ENABLE_ASSERTIONS \
 	ENABLE_BTI \
@@ -1433,6 +1437,7 @@
 	BL2_INV_DCACHE \
 	USE_SPINLOCK_CAS \
 	ERRATA_SPECULATIVE_AT \
+	ERRATA_SME_POWER_DOWN \
 	RAS_TRAP_NS_ERR_REC_ACCESS \
 	COT_DESC_IN_DTB \
 	USE_SP804_TIMER \
@@ -1450,7 +1455,7 @@
 	ENABLE_TRF_FOR_NS \
 	ENABLE_FEAT_HCX \
 	ENABLE_MPMM \
-	ENABLE_MPMM_FCONF \
+	FEAT_PABANDON \
 	ENABLE_FEAT_FGT \
 	ENABLE_FEAT_FGT2 \
 	ENABLE_FEAT_FPMR \
@@ -1633,12 +1638,28 @@
 # Expand build macros for the different images
 ifeq (${NEED_FDT},yes)
     $(eval $(call MAKE_DTBS,$(BUILD_PLAT)/fdts,$(FDT_SOURCES)))
+
+    ifneq (${INITRD_SIZE}${INITRD_PATH},)
+        ifndef INITRD_BASE
+            $(error INITRD_BASE must be set when inserting initrd properties to the DTB.)
+        endif
+
+        INITRD_SIZE ?= $(shell printf "0x%x\n" $$(stat -Lc %s $(INITRD_PATH)))
+        initrd_end = $(shell printf "0x%x\n" $$(expr $$(($(INITRD_BASE) + $(INITRD_SIZE)))))
+
+        define $(HW_CONFIG)-after +=
+            $(s)echo "  INITRD  $(HW_CONFIG)"
+            $(q)fdtput -t x $@ /chosen linux,initrd-start $(INITRD_BASE)
+            $(q)fdtput -t x $@ /chosen linux,initrd-end $(initrd_end)
+        endef
+    endif
 endif #(NEED_FDT)
 
 # Add Secure Partition packages
 ifeq (${NEED_SP_PKG},yes)
 $(BUILD_PLAT)/sp_gen.mk: ${SP_MK_GEN} ${SP_LAYOUT_FILE} | $$(@D)/
-	$(q)${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT} ${SP_DTS_LIST_FRAGMENT}
+	$(if $(host-poetry),$(q)poetry -q install)
+	$(q)$(if $(host-poetry),poetry run )${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT} ${SP_DTS_LIST_FRAGMENT}
 sp: $(DTBS) $(BUILD_PLAT)/sp_gen.mk $(SP_PKGS)
 	$(s)echo
 	$(s)echo "Built SP Images successfully"
@@ -1757,8 +1778,8 @@
 	$(q)${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} CRYPTO_SUPPORT=${CRYPTO_SUPPORT} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES=$(call escape-shell,$(INCLUDES)) DEFINES=$(call escape-shell,$(DEFINES)) --no-print-directory -C ${ROMLIBPATH} all
 
 memmap: all
-	$(q)PYTHONPATH=${CURDIR}/tools/memory \
-		${PYTHON} -m memory.memmap -sr ${BUILD_PLAT}
+	$(if $(host-poetry),$(q)poetry -q install)
+	$(q)$(if $(host-poetry),poetry run )memory -sr ${BUILD_PLAT}
 
 tl: ${BUILD_PLAT}/tl.bin
 ${BUILD_PLAT}/tl.bin: ${HW_CONFIG}
diff --git a/bl1/bl1.mk b/bl1/bl1.mk
index a8a0061..c068ea5 100644
--- a/bl1/bl1.mk
+++ b/bl1/bl1.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -18,8 +18,7 @@
 				${MBEDTLS_SOURCES}
 
 ifeq (${ARCH},aarch64)
-BL1_SOURCES		+=	lib/cpus/aarch64/dsu_helpers.S		\
-				lib/el3_runtime/aarch64/context.S	\
+BL1_SOURCES		+=	lib/el3_runtime/aarch64/context.S	\
 				lib/cpus/errata_common.c
 endif
 
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
index 850d826..2a212e1 100644
--- a/bl2/bl2.mk
+++ b/bl2/bl2.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -43,10 +43,6 @@
 				bl2/${ARCH}/bl2_run_next_image.S        \
 				lib/cpus/${ARCH}/cpu_helpers.S
 
-ifeq (${ARCH},aarch64)
-BL2_SOURCES		+=	lib/cpus/aarch64/dsu_helpers.S
-endif
-
 BL2_DEFAULT_LINKER_SCRIPT_SOURCE := bl2/bl2_el3.ld.S
 endif
 
diff --git a/bl31/aarch64/ea_delegate.S b/bl31/aarch64/ea_delegate.S
index 91ea75d..fce17e1 100644
--- a/bl31/aarch64/ea_delegate.S
+++ b/bl31/aarch64/ea_delegate.S
@@ -245,26 +245,30 @@
  */
 func ea_proceed
 	/*
-	 * If the ESR loaded earlier is not zero, we were processing an EA
-	 * already, and this is a double fault.
+	 * If it is a double fault invoke platform handler.
+	 * Double fault scenario would arise when platform is handling a fault in
+	 * lower EL using plat_ea_handler() and another fault happens which would
+	 * trap into EL3 as FFH_SUPPORT is enabled for the platform.
 	 */
-	ldr	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
+	ldr	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_DOUBLE_FAULT_ESR]
 	cbz	x5, 1f
 	no_ret	plat_handle_double_fault
 
 1:
-	/* Save EL3 state */
+	/* Save EL3 state as handling might involve lower ELs */
 	mrs	x2, spsr_el3
 	mrs	x3, elr_el3
 	stp	x2, x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+	mrs	x4, scr_el3
+	str	x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
 
 	/*
-	 * Save ESR as handling might involve lower ELs, and returning back to
-	 * EL3 from there would trample the original ESR.
+	 * Save CTX_DOUBLE_FAULT_ESR, so that if another fault happens in lower EL, we
+	 * catch it as DoubleFault in next invocation of ea_proceed() along with
+	 * preserving original ESR_EL3.
 	 */
-	mrs	x4, scr_el3
 	mrs	x5, esr_el3
-	stp	x4, x5, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+	str	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_DOUBLE_FAULT_ESR]
 
 	/*
 	 * Setup rest of arguments, and call platform External Abort handler.
@@ -305,23 +309,15 @@
 	/* Make SP point to context */
 	msr	spsel, #MODE_SP_ELX
 
-	/* Restore EL3 state and ESR */
+	/* Clear Double Fault storage */
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_DOUBLE_FAULT_ESR]
+
+	/* Restore EL3 state */
 	ldp	x1, x2, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
 	msr	spsr_el3, x1
 	msr	elr_el3, x2
-
-	/* Restore ESR_EL3 and SCR_EL3 */
-	ldp	x3, x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+	ldr	x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
 	msr	scr_el3, x3
-	msr	esr_el3, x4
-
-#if ENABLE_ASSERTIONS
-	cmp	x4, xzr
-	ASM_ASSERT(ne)
-#endif
-
-	/* Clear ESR storage */
-	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
 
 	ret	x29
 endfunc ea_proceed
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 2f9dc65..e390915 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -24,7 +24,6 @@
 endif
 
 include lib/extensions/amu/amu.mk
-include lib/mpmm/mpmm.mk
 
 ifeq (${SPMC_AT_EL3},1)
   $(info Including EL3 SPMC makefile)
@@ -43,7 +42,6 @@
 				bl31/bl31_traps.c				\
 				common/runtime_svc.c				\
 				lib/cpus/errata_common.c			\
-				lib/cpus/aarch64/dsu_helpers.S			\
 				plat/common/aarch64/platform_mp_stack.S		\
 				services/arm_arch_svc/arm_arch_svc_setup.c	\
 				services/std_svc/std_svc_setup.c		\
@@ -115,10 +113,6 @@
 BL31_SOURCES		+=	lib/extensions/tcr/tcr2.c
 endif
 
-ifeq (${ENABLE_MPMM},1)
-BL31_SOURCES		+=	${MPMM_SOURCES}
-endif
-
 ifneq (${ENABLE_SME_FOR_NS},0)
 BL31_SOURCES		+=	lib/extensions/sme/sme.c
 endif
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index 83be0f6..db0ea6c 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -127,7 +127,7 @@
 void bl31_main(void)
 {
 	/* Init registers that never change for the lifetime of TF-A */
-	cm_manage_extensions_el3();
+	cm_manage_extensions_el3(plat_my_core_pos());
 
 	/* Init per-world context registers for non-secure world */
 	manage_extensions_nonsecure_per_world();
diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c
index b213ffa..8638351 100644
--- a/common/fdt_wrappers.c
+++ b/common/fdt_wrappers.c
@@ -277,7 +277,7 @@
 	return err;
 }
 
-static uint64_t fdt_read_prop_cells(const fdt32_t *prop, int nr_cells)
+uint64_t fdt_read_prop_cells(const fdt32_t *prop, int nr_cells)
 {
 	uint64_t reg = fdt32_to_cpu(prop[0]);
 
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index 210ae7e..3e33824 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -387,7 +387,7 @@
 
 Firmware Encryption Framework
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-:|M|: Sumit Garg <sumit.garg@linaro.org>
+:|M|: Sumit Garg <sumit.garg@kernel.org>
 :|G|: `b49020`_
 :|F|: drivers/io/io_encrypted.c
 :|F|: include/drivers/io/io_encrypted.h
@@ -447,8 +447,7 @@
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Chris Kay <chris.kay@arm.com>
 :|G|: `CJKay`_
-:|F|: include/lib/mpmm/
-:|F|: lib/mpmm/
+:|F|: include/lib/cpus/aarch64/cpu_macros.S
 
 Granule Protection Tables Library (GPT-RME)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -896,7 +895,7 @@
 
 Synquacer platform port
 ^^^^^^^^^^^^^^^^^^^^^^^
-:|M|: Sumit Garg <sumit.garg@linaro.org>
+:|M|: Sumit Garg <sumit.garg@kernel.org>
 :|G|: `b49020`_
 :|M|: Masahisa Kojima <kojima.masahisa@socionext.com>
 :|G|: `masahisak`_
@@ -997,7 +996,7 @@
 
 Encrypt_fw tool
 ^^^^^^^^^^^^^^^
-:|M|: Sumit Garg <sumit.garg@linaro.org>
+:|M|: Sumit Garg <sumit.garg@kernel.org>
 :|G|: `b49020`_
 :|F|: tools/encrypt_fw/
 
diff --git a/docs/components/activity-monitors.rst b/docs/components/activity-monitors.rst
index 5c1c2c2..4c33d42 100644
--- a/docs/components/activity-monitors.rst
+++ b/docs/components/activity-monitors.rst
@@ -20,15 +20,9 @@
 build option.
 
 As a security precaution, Trusted Firmware-A does not enable these by default.
-Instead, platforms may configure their auxiliary counters through one of two
-possible mechanisms:
-
-- |FCONF|, controlled by the ``ENABLE_AMU_FCONF`` build option.
-- A platform implementation of the ``plat_amu_topology`` function (the default).
-
-See :ref:`Activity Monitor Unit (AMU) Bindings` for documentation on the |FCONF|
-device tree bindings.
+Instead, platforms must configure their auxiliary counters through the
+``plat_amu_aux_enables`` platform hook.
 
 --------------
 
-*Copyright (c) 2021, Arm Limited. All rights reserved.*
+*Copyright (c) 2021-2025, Arm Limited. All rights reserved.*
diff --git a/docs/components/context-management-library.rst b/docs/components/context-management-library.rst
index 6a76ada..8cb1ace 100644
--- a/docs/components/context-management-library.rst
+++ b/docs/components/context-management-library.rst
@@ -498,7 +498,6 @@
 
 	typedef struct per_world_context {
 		uint64_t ctx_cptr_el3;
-		uint64_t ctx_zcr_el3;
 		uint64_t ctx_mpam3_el3;
 	} per_world_context_t;
 
@@ -555,7 +554,7 @@
 EL3 execution context needs to setup at both boot time (cold and warm boot)
 entrypaths and at all the possible exception handlers routing to EL3 at runtime.
 
-*Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.*
 
 .. |Context Memory Allocation| image:: ../resources/diagrams/context_memory_allocation.png
 .. |CPU Context Memory Configuration| image:: ../resources/diagrams/cpu_data_config_context_memory.png
diff --git a/docs/components/fconf/amu-bindings.rst b/docs/components/fconf/amu-bindings.rst
deleted file mode 100644
index 047f75e..0000000
--- a/docs/components/fconf/amu-bindings.rst
+++ /dev/null
@@ -1,142 +0,0 @@
-Activity Monitor Unit (AMU) Bindings
-====================================
-
-To support platform-defined Activity Monitor Unit (|AMU|) auxiliary counters
-through FCONF, the ``HW_CONFIG`` device tree accepts several |AMU|-specific
-nodes and properties.
-
-Bindings
-^^^^^^^^
-
-.. contents::
-    :local:
-
-``/cpus/cpus/cpu*`` node properties
-"""""""""""""""""""""""""""""""""""
-
-The ``cpu`` node has been augmented to support a handle to an associated |AMU|
-view, which should describe the counters offered by the core.
-
-+---------------+-------+---------------+-------------------------------------+
-| Property name | Usage | Value type    | Description                         |
-+===============+=======+===============+=====================================+
-| ``amu``       | O     | ``<phandle>`` | If present, indicates that an |AMU| |
-|               |       |               | is available and its counters are   |
-|               |       |               | described by the node provided.     |
-+---------------+-------+---------------+-------------------------------------+
-
-``/cpus/amus`` node properties
-""""""""""""""""""""""""""""""
-
-The ``amus`` node describes the |AMUs| implemented by the cores in the system.
-This node does not have any properties.
-
-``/cpus/amus/amu*`` node properties
-"""""""""""""""""""""""""""""""""""
-
-An ``amu`` node describes the layout and meaning of the auxiliary counter
-registers of one or more |AMUs|, and may be shared by multiple cores.
-
-+--------------------+-------+------------+------------------------------------+
-| Property name      | Usage | Value type | Description                        |
-+====================+=======+============+====================================+
-| ``#address-cells`` | R     | ``<u32>``  | Value shall be 1. Specifies that   |
-|                    |       |            | the ``reg`` property array of      |
-|                    |       |            | children of this node uses a       |
-|                    |       |            | single cell.                       |
-+--------------------+-------+------------+------------------------------------+
-| ``#size-cells``    | R     | ``<u32>``  | Value shall be 0. Specifies that   |
-|                    |       |            | no size is required in the ``reg`` |
-|                    |       |            | property in children of this node. |
-+--------------------+-------+------------+------------------------------------+
-
-``/cpus/amus/amu*/counter*`` node properties
-""""""""""""""""""""""""""""""""""""""""""""
-
-A ``counter`` node describes an auxiliary counter belonging to the parent |AMU|
-view.
-
-+-------------------+-------+-------------+------------------------------------+
-| Property name     | Usage | Value type  | Description                        |
-+===================+=======+=============+====================================+
-| ``reg``           | R     | array       | Represents the counter register    |
-|                   |       |             | index, and must be a single cell.  |
-+-------------------+-------+-------------+------------------------------------+
-| ``enable-at-el3`` | O     | ``<empty>`` | The presence of this property      |
-|                   |       |             | indicates that this counter should |
-|                   |       |             | be enabled prior to EL3 exit.      |
-+-------------------+-------+-------------+------------------------------------+
-
-Example
-^^^^^^^
-
-An example system offering four cores made up of two clusters, where the cores
-of each cluster share different |AMUs|, may use something like the following:
-
-.. code-block::
-
-    cpus {
-        #address-cells = <2>;
-        #size-cells = <0>;
-
-        amus {
-            amu0: amu-0 {
-                #address-cells = <1>;
-                #size-cells = <0>;
-
-                counterX: counter@0 {
-                    reg = <0>;
-
-                    enable-at-el3;
-                };
-
-                counterY: counter@1 {
-                    reg = <1>;
-
-                    enable-at-el3;
-                };
-            };
-
-            amu1: amu-1 {
-                #address-cells = <1>;
-                #size-cells = <0>;
-
-                counterZ: counter@0 {
-                    reg = <0>;
-
-                    enable-at-el3;
-                };
-            };
-        };
-
-        cpu0@00000 {
-            ...
-
-            amu = <&amu0>;
-        };
-
-        cpu1@00100 {
-            ...
-
-            amu = <&amu0>;
-        };
-
-        cpu2@10000 {
-            ...
-
-            amu = <&amu1>;
-        };
-
-        cpu3@10100 {
-            ...
-
-            amu = <&amu1>;
-        };
-    }
-
-In this situation, ``cpu0`` and ``cpu1`` (the two cores in the first cluster),
-share the view of their AMUs defined by ``amu0``. Likewise, ``cpu2`` and
-``cpu3`` (the two cores in the second cluster), share the view of their |AMUs|
-defined by ``amu1``. This will cause ``counterX`` and ``counterY`` to be enabled
-for both ``cpu0`` and ``cpu1``, and ``counterZ`` to be enabled for both ``cpu2``
-and ``cpu3``.
diff --git a/docs/components/fconf/index.rst b/docs/components/fconf/index.rst
index b8b4519..6cb6774 100644
--- a/docs/components/fconf/index.rst
+++ b/docs/components/fconf/index.rst
@@ -145,6 +145,4 @@
   :maxdepth: 1
 
   fconf_properties
-  amu-bindings
-  mpmm-bindings
   tb_fw_bindings
diff --git a/docs/components/fconf/mpmm-bindings.rst b/docs/components/fconf/mpmm-bindings.rst
deleted file mode 100644
index d3cc857..0000000
--- a/docs/components/fconf/mpmm-bindings.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-Maximum Power Mitigation Mechanism (MPMM) Bindings
-==================================================
-
-|MPMM| support cannot be determined at runtime by the firmware. Instead, these
-DTB bindings allow the platform to communicate per-core support for |MPMM| via
-the ``HW_CONFIG`` device tree blob.
-
-Bindings
-^^^^^^^^
-
-.. contents::
-    :local:
-
-``/cpus/cpus/cpu*`` node properties
-"""""""""""""""""""""""""""""""""""
-
-The ``cpu`` node has been augmented to allow the platform to indicate support
-for |MPMM| on a given core.
-
-+-------------------+-------+-------------+------------------------------------+
-| Property name     | Usage | Value type  | Description                        |
-+===================+=======+=============+====================================+
-| ``supports-mpmm`` | O     | ``<empty>`` | If present, indicates that |MPMM|  |
-|                   |       |             | is available on this core.         |
-+-------------------+-------+-------------+------------------------------------+
-
-Example
-^^^^^^^
-
-An example system offering two cores, one with support for |MPMM| and one
-without, can be described as follows:
-
-.. code-block::
-
-    cpus {
-        #address-cells = <2>;
-        #size-cells = <0>;
-
-        cpu0@00000 {
-            ...
-
-            supports-mpmm;
-        };
-
-        cpu1@00100 {
-            ...
-        };
-    }
diff --git a/docs/components/granule-protection-tables-design.rst b/docs/components/granule-protection-tables-design.rst
index 78d2f12..91673c6 100644
--- a/docs/components/granule-protection-tables-design.rst
+++ b/docs/components/granule-protection-tables-design.rst
@@ -124,10 +124,7 @@
 
 The GPT initialization APIs require memory to be passed in for the tables to be
 constructed. The ``gpt_init_l0_tables`` API takes a memory address and size for
-building the level 0 tables and also memory for allocating the fine-grained bitlock
-data structure. The amount of memory needed for bitlock structure is controlled via
-``RME_GPT_BITLOCK_BLOCK`` config which defines the block size for each bit of the
-the bitlock.
+building the level 0 tables.
 
 The ``gpt_init_pas_l1_tables`` API takes an address and size for
 building the level 1 tables which are linked from level 0 descriptors. The
@@ -156,7 +153,7 @@
 During Granule Transition access to L1 tables is controlled by a lock to ensure
 that no more than one CPU is allowed to make changes at any given time.
 The granularity of the lock is defined by ``RME_GPT_BITLOCK_BLOCK`` build option
-which defines the size of the memory block protected by one bit of ``bitlock``
+which defines the size of the memory block protected by one bit of ``bitlock_t``
 structure. Setting this option to 0 chooses a single spinlock for all GPT L1
 table entries.
 
@@ -185,6 +182,10 @@
 #. In systems that make use of the granule transition service, runtime
    firmware must call ``gpt_runtime_init`` to set up the data structures needed
    by the GTSI to find the tables and transition granules between PAS types.
+   The base address of bitlocks array and its size are provided to this function
+   as arguments. These parameters are not used in case of a single spinlock for
+   all GPT L1 table entries(``RME_GPT_BITLOCK_BLOCK`` is 0) and are passed as zero
+   values.
 
 API Constraints
 ~~~~~~~~~~~~~~~
@@ -225,9 +226,6 @@
   is greater. L0 table size is the total protected space (PPS) divided by the
   size of each L0 region (L0GPTSZ) multiplied by the size of each L0 descriptor
   (8 bytes). ((PPS / L0GPTSZ) * 8)
-* The L0 memory size must be greater than the table size and have enough space
-  to allocate array of ``bitlock`` structures at the end of L0 table if
-  required (``RME_GPT_BITLOCK_BLOCK`` is not 0).
 * The L0 memory must fall within a PAS of type GPT_GPI_ROOT.
 
 The L1 memory also has some constraints.
@@ -237,6 +235,10 @@
   the granules controlled in each byte (2). ((L0GPTSZ / PGS) / 2)
 * There must be enough L1 memory supplied to build all requested L1 tables.
 * The L1 memory must fall within a PAS of type GPT_GPI_ROOT.
+* The platform allocates the bitlock array which contains fine-grained
+  ``bitlock_t`` data structures. The RME GPT library will check that the array
+  has at least the amount of memory defined by PPS and ``RME_GPT_BITLOCK_BLOCK``
+  value.
 
 If an invalid combination of parameters is supplied, the APIs will print an
 error message and return a negative value. The return values of APIs should be
@@ -245,7 +247,7 @@
 Sample Calculation for L0 memory size and alignment
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Let PPS=GPCCR_PPS_4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
+Let PPS=4GB and L0GPTSZ=GPCCR_L0GPTSZ_30BITS
 
 We can find the total L0 table size with ((PPS / L0GPTSZ) * 8)
 
@@ -254,19 +256,19 @@
 And solve to get 32 bytes. In this case, 4096 is greater than 32, so the L0
 tables must be aligned to 4096 bytes.
 
-Sample calculation for bitlock array size
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sample calculation for bitlocks array size
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Let PGS=GPCCR_PPS_256TB and RME_GPT_BITLOCK_BLOCK=1
+Let PPS=256TB and RME_GPT_BITLOCK_BLOCK=1
 
-The size of bit lock array in bits is the total protected space (PPS) divided
+The size of bitlocks array in bits is the total protected space (PPS) divided
 by the size of memory block per bit. The size of memory block
 is ``RME_GPT_BITLOCK_BLOCK`` (number of 512MB blocks per bit) times
-512MB (0x20000000). This is then divided by the number of bits in ``bitlock``
-structure (8) to get the size of bit array in bytes.
+512MB (0x20000000). This is then divided by the number of bits in ``bitlock_t``
+structure (8) to get the size of array in bytes.
 
-In other words, we can find the total size of ``bitlock`` array
-in bytes with PPS / (RME_GPT_BITLOCK_BLOCK * 0x20000000 *  8).
+In other words, we can find the total size of ``bitlock_t`` array
+in bytes with PPS / (RME_GPT_BITLOCK_BLOCK * 0x20000000 * 8).
 
 Substitute values to get this: 0x1000000000000 / (1 * 0x20000000 * 8)
 
diff --git a/docs/components/mpmm.rst b/docs/components/mpmm.rst
index 1b1c6d8..aaa9481 100644
--- a/docs/components/mpmm.rst
+++ b/docs/components/mpmm.rst
@@ -8,16 +8,7 @@
 triggering of whole-rail (i.e. clock chopping) responses to overcurrent
 conditions.
 
-|MPMM| is enabled on a per-core basis by the EL3 runtime firmware. The presence
-of |MPMM| cannot be determined at runtime by the firmware, and therefore the
-platform must expose this information through one of two possible mechanisms:
-
-- |FCONF|, controlled by the ``ENABLE_MPMM_FCONF`` build option.
-- A platform implementation of the ``plat_mpmm_topology`` function (the
-  default).
-
-See :ref:`Maximum Power Mitigation Mechanism (MPMM) Bindings` for documentation
-on the |FCONF| device tree bindings.
+|MPMM| is enabled on a per-core basis by the EL3 runtime firmware.
 
 .. warning::
 
diff --git a/docs/components/rmm-el3-comms-spec.rst b/docs/components/rmm-el3-comms-spec.rst
index 79e1d2c..f1ca031 100644
--- a/docs/components/rmm-el3-comms-spec.rst
+++ b/docs/components/rmm-el3-comms-spec.rst
@@ -53,7 +53,7 @@
     consistency with the versioning schemes used in other parts of RMM.
 
 This document specifies the 0.4 version of Boot Interface ABI and RMM-EL3
-services specification and the 0.3 version of the Boot Manifest.
+services specification and the 0.4 version of the Boot Manifest.
 
 .. _rmm_el3_boot_interface:
 
@@ -182,12 +182,12 @@
 
 This Boot Manifest is versioned independently of the Boot Interface, to help
 evolve the former independent of the latter.
-The current version for the Boot Manifest is ``v0.3`` and the rules explained
+The current version for the Boot Manifest is ``v0.4`` and the rules explained
 in :ref:`rmm_el3_ifc_versioning` apply on this version as well.
 
-The Boot Manifest v0.3 has the following fields:
+The Boot Manifest v0.4 has the following fields:
 
-   - version : Version of the Manifest (v0.3)
+   - version : Version of the Manifest (v0.4)
    - plat_data : Pointer to the platform specific data and not specified by this
      document. These data are optional and can be NULL.
    - plat_dram : Structure encoding the NS DRAM information on the platform. This
@@ -720,61 +720,65 @@
 RMM-EL3 Boot Manifest structure
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The RMM-EL3 Boot Manifest v0.3 structure contains platform boot information passed
-from EL3 to RMM. The size of the Boot Manifest is 64 bytes.
+The RMM-EL3 Boot Manifest v0.4 structure contains platform boot information passed
+from EL3 to RMM. The size of the Boot Manifest is 112 bytes.
 
 The members of the RMM-EL3 Boot Manifest structure are shown in the following
 table:
 
-+--------------+--------+----------------+----------------------------------------+
-|   Name       | Offset |     Type       |               Description              |
-+==============+========+================+========================================+
-| version      |   0    |   uint32_t     | Boot Manifest version                  |
-+--------------+--------+----------------+----------------------------------------+
-| padding      |   4    |   uint32_t     | Reserved, set to 0                     |
-+--------------+--------+----------------+----------------------------------------+
-| plat_data    |   8    |   uintptr_t    | Pointer to Platform Data section       |
-+--------------+--------+----------------+----------------------------------------+
-| plat_dram    |   16   | ns_dram_info   | NS DRAM Layout Info structure          |
-+--------------+--------+----------------+----------------------------------------+
-| plat_console |   40   | console_list   | List of consoles available to RMM      |
-+--------------+--------+----------------+----------------------------------------+
++--------------------+--------+-------------------+----------------------------------------------+
+|   Name             | Offset |       Type        |            Description                       |
++====================+========+===================+==============================================+
+| version            |   0    |      uint32_t     | Boot Manifest version                        |
++--------------------+--------+-------------------+----------------------------------------------+
+| padding            |   4    |      uint32_t     | Reserved, set to 0                           |
++--------------------+--------+-------------------+----------------------------------------------+
+| plat_data          |   8    |     uintptr_t     | Pointer to Platform Data section             |
++--------------------+--------+-------------------+----------------------------------------------+
+| plat_dram          |   16   |    memory_info    | NS DRAM Layout Info structure                |
++--------------------+--------+-------------------+----------------------------------------------+
+| plat_console       |   40   |   console_list    | List of consoles available to RMM            |
++--------------------+--------+-------------------+----------------------------------------------+
+| plat_ncoh_region   |   64   |    memory_info    | Device non-coherent ranges Info structure    |
++--------------------+--------+-------------------+----------------------------------------------+
+| plat_coh_region    |   88   |    memory_info    | Device coherent ranges Info structure        |
++--------------------+--------+-------------------+----------------------------------------------+
 
-.. _ns_dram_info_struct:
+.. _memory_info_struct:
 
-NS DRAM Layout Info structure
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Memory Info structure
+~~~~~~~~~~~~~~~~~~~~~~
 
-NS DRAM Layout Info structure contains information about platform Non-secure
-DRAM layout. The members of this structure are shown in the table below:
+Memory Info structure contains information about platform memory layout.
+The members of this structure are shown in the table below:
 
 +-----------+--------+----------------+----------------------------------------+
 |   Name    | Offset |     Type       |               Description              |
 +===========+========+================+========================================+
-| num_banks |   0    |   uint64_t     | Number of NS DRAM banks                |
+| num_banks |   0    |   uint64_t     | Number of memory banks/device regions  |
 +-----------+--------+----------------+----------------------------------------+
-| banks     |   8    | ns_dram_bank * | Pointer to 'ns_dram_bank'[] array      |
+| banks     |   8    |  memory_bank * | Pointer to 'memory_bank'[] array       |
 +-----------+--------+----------------+----------------------------------------+
 | checksum  |   16   |   uint64_t     | Checksum                               |
 +-----------+--------+----------------+----------------------------------------+
 
 Checksum is calculated as two's complement sum of 'num_banks', 'banks' pointer
-and DRAM banks data array pointed by it.
+and memory banks data array pointed by it.
 
-.. _ns_dram_bank_struct:
+.. _memory_bank_struct:
 
-NS DRAM Bank structure
-~~~~~~~~~~~~~~~~~~~~~~
+Memory Bank/Device region structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-NS DRAM Bank structure contains information about each Non-secure DRAM bank:
+Memory Bank structure contains information about each memory bank/device region:
 
-+-----------+--------+----------------+----------------------------------------+
-|   Name    | Offset |     Type       |               Description              |
-+===========+========+================+========================================+
-|   base    |   0    |   uintptr_t    | Base address                           |
-+-----------+--------+----------------+----------------------------------------+
-|   size    |   8    |   uint64_t     | Size of bank in bytes                  |
-+-----------+--------+----------------+----------------------------------------+
++-----------+--------+----------------+--------------------------------------------+
+|   Name    | Offset |     Type       |                Description                 |
++===========+========+================+============================================+
+|   base    |   0    |   uintptr_t    | Base address                               |
++-----------+--------+----------------+--------------------------------------------+
+|   size    |   8    |   uint64_t     | Size of memory bank/device region in bytes |
++-----------+--------+----------------+--------------------------------------------+
 
 .. _console_list_struct:
 
@@ -784,15 +788,15 @@
 Console List structure contains information about the available consoles for RMM.
 The members of this structure are shown in the table below:
 
-+--------------+--------+----------------+----------------------------------------+
-|   Name       | Offset |     Type       |               Description              |
-+==============+========+================+========================================+
-| num_consoles |   0    |   uint64_t     | Number of consoles                     |
-+--------------+--------+----------------+----------------------------------------+
-| consoles     |   8    | console_info * | Pointer to 'console_info'[] array      |
-+--------------+--------+----------------+----------------------------------------+
-| checksum     |   16   |   uint64_t     | Checksum                               |
-+--------------+--------+----------------+----------------------------------------+
++--------------+--------+----------------+-------------------------------------+
+|   Name       | Offset |     Type       |               Description           |
++==============+========+================+=====================================+
+| num_consoles |   0    |   uint64_t     | Number of consoles                  |
++--------------+--------+----------------+-------------------------------------+
+| consoles     |   8    | console_info * | Pointer to 'console_info'[] array   |
++--------------+--------+----------------+-------------------------------------+
+| checksum     |   16   |   uint64_t     | Checksum                            |
++--------------+--------+----------------+-------------------------------------+
 
 Checksum is calculated as two's complement sum of 'num_consoles', 'consoles'
 pointer and the consoles array pointed by it.
@@ -804,28 +808,28 @@
 
 Console Info structure contains information about each Console available to RMM.
 
-+-----------+--------+---------------+----------------------------------------+
-|   Name    | Offset |     Type      |               Description              |
-+===========+========+===============+========================================+
-| base      |   0    |   uintptr_t   | Console Base address                   |
-+-----------+--------+---------------+----------------------------------------+
-| map_pages |   8    |   uint64_t    | Num of pages to map for console MMIO   |
-+-----------+--------+---------------+----------------------------------------+
-| name      |   16   |   char[]      | Name of console                        |
-+-----------+--------+---------------+----------------------------------------+
-| clk_in_hz |   24   |   uint64_t    | UART clock (in hz) for console         |
-+-----------+--------+---------------+----------------------------------------+
-| baud_rate |   32   |   uint64_t    | Baud rate                              |
-+-----------+--------+---------------+----------------------------------------+
-| flags     |   40   |   uint64_t    | Additional flags (RES0)                |
-+-----------+--------+---------------+----------------------------------------+
++-----------+--------+---------------+-----------------------------------------+
+|   Name    | Offset |     Type      |               Description               |
++===========+========+===============+=========================================+
+| base      |   0    |   uintptr_t   | Console Base address                    |
++-----------+--------+---------------+-----------------------------------------+
+| map_pages |   8    |   uint64_t    | Num of pages to map for console MMIO    |
++-----------+--------+---------------+-----------------------------------------+
+| name      |   16   |   char[8]     | Name of console                         |
++-----------+--------+---------------+-----------------------------------------+
+| clk_in_hz |   24   |   uint64_t    | UART clock (in Hz) for console          |
++-----------+--------+---------------+-----------------------------------------+
+| baud_rate |   32   |   uint64_t    | Baud rate                               |
++-----------+--------+---------------+-----------------------------------------+
+| flags     |   40   |   uint64_t    | Additional flags (RES0)                 |
++-----------+--------+---------------+-----------------------------------------+
 
 .. _el3_token_sign_request_struct:
 
 EL3 Token Sign Request structure
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-This structure represents a realm attestation toekn signing request.
+This structure represents a realm attestation token signing request.
 
 +-------------+--------+---------------+-----------------------------------------+
 |   Name      | Offset |     Type      |               Description               |
diff --git a/docs/design/console-framework.rst b/docs/design/console-framework.rst
new file mode 100644
index 0000000..fcd2e68
--- /dev/null
+++ b/docs/design/console-framework.rst
@@ -0,0 +1,341 @@
+Console Framework
+=================
+
+The TF-A console framework is used to register consoles for different boot states
+so that user's output can be displayed on physical consoles throughout the different
+boot stages. The framework also supports debug mode for general debugging purposes.
+
+The console framework supports a number of different UARTs, it is highly likely
+that the driver of the UART that is needed is already implemented. If not, a driver
+will need to be written for the new UART in TF-A. Current supported UARTs are:
+
+* Amlogic Meson
+* Arm PL011
+* Cadence CDNS
+* Coreboot CBMEM
+* Marvell A3700
+* NXP
+    * i.MX LPUART
+    * i.MX UART
+    * Linflex
+* Nvidia SPE
+* Qualcomm UARTDM
+* Renesas RCAR
+* STMicroelectronics STM32
+* Texas Instruments 16550
+
+    .. note::
+        The supported UART list is non-exhaustive. Check if the UART driver has
+        already been written before writing a new one.
+
+::
+
+    Console scopes and flags
+
+    Scope   : Flag
+    BOOT    : CONSOLE_FLAG_BOOT
+    RUNTIME : CONSOLE_FLAG_RUNTIME
+    CRASH   : CONSOLE_FLAG_CRASH
+
+The console framework supports multiple consoles. Multiple instances of a UART
+can be registered at any given moment. Any registered console can have a single
+scope or multiple scopes. In single scope for example, setting three different
+consoles with each having BOOT, RUNTIME, and CRASH states respectively, the boot
+console will display only boot logs, the runtime console will display only the
+runtime output, while the crash console will be used to print the crash log in the
+event of a crash. Similarly, a console with all three scopes will display any and
+all output destined for BOOT, RUNTIME, or CRASH consoles.
+
+These multiple scopes can be useful in many ways, for example:
+
+* Having different consoles for Boot and Runtime messages
+* Having a single console for both Runtime and Boot messages
+* Having no runtime console at all and just having a single Boot console.
+* Having a separate console for crash reporting when debugging.
+
+.. Registering a console:
+
+Registering a console
+---------------------
+To register a console in TF-A check if the hardware (UART) that is going to be used
+is already defined, if not we will need to define it, for example, the **PL011**
+UART driver API is defined in ``include/drivers/arm/pl011.h``.
+
+A skeleton console driver (assembly) is provided in TF-A ``drivers/console/aarch64/
+skeleton_console.S``, this skeleton sets the rules for writing a new console_driver.
+Have a look at ``drivers/arm/pl011/aarch64/pl011_console.S`` for an actual
+implementation using this skeleton.
+
+Function : console_xxx_register
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : console_t *, ...
+    Return   : int
+
+This ASM Function is used to initialize and register a console. The caller needs
+to pass an empty ``console_t`` struct which *MUST* be allocated in persistent
+memory (e.g. a global or static local variable, *NOT* on the stack).
+
+This function takes a ``console_t`` struct placed in x0 and additional
+arguments placed in x1 - x7. It returns x0 with either a 0 on failure or 1
+on success.
+
+See ``console_pl011_register`` ASM function for an implementation of this
+function.
+
+    .. note::
+        The ``xxx`` in the function name is replaced with the console driver
+        name, for example, ``console_xxx_register`` becomes
+        ``console_pl011_register`` in the driver for pl011.
+
+Function : console_xxx_putc
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int, console_t *
+    Return   : int
+
+This ASM function is used to send a character to the UART's Transmit FIFO. It takes
+two arguments, a character as int stored in w0, and the ``console_t`` struct pointer
+stored in x1. It returns w0 with either the character on successs or a negative
+value on error. In a crash context this function must only clobber x0 - x2, x16 - x17.
+
+See ``console_pl011_putc`` ASM function for an implementation.
+
+    .. note::
+        Avoid the direct use of this function for printing to the console, instead use
+        the ``debug.h`` print macros, such as: VERBOSE(...), INFO(...), WARN(...),
+        NOTICE(...) and ERROR(...).
+
+Function : console_xxx_getc
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : console_t *
+    Return   : int
+
+This ASM function is used to read a character from the receive FIFO. It takes a pointer
+to the console_struct as an argument and returns a character on success or a negative
+value below -2 on failure. This function is dependent on the ``ENABLE_CONSOLE_GETC`` flag,
+which is optional and is left to the platform because there may be security implications.
+
+See ``console_pl011_getc`` ASM function for an implementation.
+
+Function : console_xxx_flush
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : console_t *
+    Return   : void
+
+This ASM function flushes any characters, that are still in the Transmit FIFO but
+haven't been printed yet to the console. It takes a pointer to the console_struct
+but doesn't return any value. In a crash context this function must only clobber
+x0 - x5, x16 - x17.
+
+See ``console_pl011_flush`` ASM function for an implementation.
+
+Macro : finish_console_register xxx putc=1 getc=ENABLE_CONSOLE_GETC flush=1
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Callbacks
+    xxx      : name of the console driver
+    putc     : 0 for off, 1 to turn on putc function
+    getc     : 0 for off, ENABLE_CONSOLE_GETC to turn on the getc function
+    flush    : 0 for off, 1 to turn on flush function
+
+This assembly macro function is called by the ``console_xxx_register`` to
+encapsulate the common setup that has to be done at the end of a console
+driver's register function. It takes ``putc``, ``getc`` and ``flush`` macro
+arguments. It will register all of the driver's callbacks in the ``console_t``
+struct and initialize the ``flags`` field (by default consoles are enabled for
+"boot" and "crash" states, this can be changed after registration using the
+``console_set_scope`` function). This macro ends with a tail call that will
+include return to the caller.
+
+This macro requires ``console_t`` pointer in x0 and a valid return address in x30.
+
+See ``include/arch/aarch64/console_macros.S``.
+
+Registering a console using C
+-----------------------------
+
+A console can be implemented in pure C, which is much easier than using assembly.
+Currently there is no C template for implementing a console driver in C but it can
+easily be implemented using existing examples. See ``drivers/arm/dcc/dcc_console.c``
+for an implementation of a console driver in C.
+
+The assembly functions in `Registering a console`_ section can be written in C when
+implementing a console driver using C.
+
+    .. note::
+        A crash callback needs to be able to run without a stack. If crash mode
+        support is required then the console driver will need to be written in
+        Assembly (only the putc and flush functions are needed in a crash
+        context).
+
+Multi Console API
+-----------------
+
+TF-A uses the multi-console API to manage the registered console instances and the
+characters print queue. This can be found in ``drivers/console/multi_console.c``.
+
+The multi-console API stores all registered consoles in a struct list ``console_list``.
+Consoles can be removed from the console_list if no longer needed.
+
+Consoles are registered with BOOT and CRASH scopes by default. These scopes can be
+changed after registration using ``console_set_scope`` function, as per the platform
+requirement.
+
+This API also helps print characters to the specified consoles, characters can also
+be retrieved from the receive FIFO (this implementation is disabled by default but can
+be enabled if there is a need for it). The API can also help flush the transmit FIFO
+to get rid of any lingering characters from the queue when switching from secure world
+to the non-secure world.
+
+The following functions are defined in the multi_console API.
+
+Function : console_register()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : console_t*
+    Return   : int
+
+This function adds a console to the ``console_list`` declared in
+``include/drivers/console.h`` and makes sure that there is only one instance
+of a specific console in this list. This function is called by the
+``finish_console_register`` asm macro function, at the end of the console
+registration process.
+
+This function always return 1. If the console is already present in the
+``console_list`` it will return immediately with a value of 1, otherwise
+it will add the console to the ``console_list`` and then return 1.
+
+    .. note::
+        The ``console_list`` is a list of type ``console_t``, it is an **extern**
+        variable declared in ``include/drivers/console.h``.
+
+Function : console_unregister()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : console_t*
+    Return   : console_t* or NULL
+
+This function removes a console from the ``console_list``. It will return the
+removed console on success or a ``NULL`` character upon failure.
+
+Function : console_set_scope()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : console_t*, int
+    Return   : void
+
+This function is used to set the scope of the registered console. A console
+can be registered with upto three states (called the scope). These states are
+
+* BOOT      - set using the flag ``CONSOLE_FLAG_BOOT``
+* RUNTIME   - set using the flag ``CONSOLE_FLAG_RUNTIME``
+* CRASH     - set using the flag ``CONSOLE_FLAG_CRASH``
+
+It takes a pointer to the console and an int value (which is provided as the
+FLAG value) as its arguments. This function does not return anything.
+
+Function : console_switch_state()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Return   : void
+
+This function sets the console state (scope) for printing, i.e, TF-A will
+start sending all logs (INFO, WARNING, ERROR, NOTICE, VERBOSE) to the consoles
+that are registered with this new state (scope). For example, calling
+``console_switch_state(CONSOLE_FLAG_RUNTIME)``, TF-A will start sending all log
+messages to all consoles marked with the RUNTIME flag. BOOT is the default
+console state.
+
+This function takes a console state as the function's only argument. This function
+does not return a value.
+
+Function : console_putc()
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Return   : int
+
+Invoking this function sends a character to the ``console->putc`` (struct
+member) function of all consoles registered for the current scope, for example,
+BOOT logs will only be printed on consoles set with a BOOT scope. In the PL011
+implementation ``console->putc`` call points to the ``console_pl011_putc()``
+function.
+
+This function takes the int value of a character as an argument and returns the
+int value of the character back on success or a negative int value on error.
+
+    .. note::
+        Do not use this function in TF-A release builds, instead use the log
+        prefixes, for example, ``INFO("Print information here.")`` to print
+        messages on the active console.
+
+Function : console_getc()
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : int
+
+This function is used to fetch a character from the receive FIFO that has
+not been printed to the console yet. This function is disabled by default for
+security reasons but can be enabled using the ``ENABLE_CONSOLE_GETC`` macro
+if there is a need for it.
+
+This function doesn't take any argument but returns a character as an int.
+
+Function : console_flush()
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function flushes all the characters pending in the transmit FIFO of the
+active UART thus removing them from the print queue.
+
+This function has no arguments and do not return a value.
+
+Function : putchar()
+~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Return   : int
+
+This function overrides the weak implementation of the putchar library. It is
+used to send a character to the ``console_putc()`` function to be printed to
+the active console.
+
+This function will either return the character on success or an **EOF** character
+otherwise.
+
+--------------
+
+*Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.*
\ No newline at end of file
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 4637908..67f29f0 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -580,6 +580,9 @@
 
 For Neoverse V3, the following errata build flags are defined :
 
+- ``ERRATA_V3_2970647``: This applies errata 2970647 workaround to Neoverse-V3
+  CPU. This needs to be enabled for revision r0p0. It is fixed in r0p1.
+
 - ``ERRATA_V3_3701767``: This applies errata 3701767 workaround to Neoverse-V3
   CPU. This needs to be enabled for revisions r0p0, r0p1, r0p2 of the CPU and
   is still open.
@@ -882,6 +885,9 @@
 - ``ERRATA_X4_2923985``: This applies errata 2923985 workaround to Cortex-X4
   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in r0p2.
 
+- ``ERRATA_X4_2957258``: This applies errata 2957258 workaround to Cortex-X4
+  CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in r0p2.
+
 - ``ERRATA_X4_3076789``: This applies errata 3076789 workaround to Cortex-X4
   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in r0p2.
 
@@ -891,6 +897,9 @@
 
 For Cortex-X925, the following errata build flags are defined :
 
+- ``ERRATA_X925_2963999``: This applies errata 2963999 workaround to Cortex-X925
+  CPU. This needs to be enabled for revision r0p0. It is fixed in r0p1.
+
 - ``ERRATA_X925_3701747``: This applies errata 3701747 workaround to Cortex-X925
   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is still open.
 
@@ -1021,7 +1030,7 @@
 For Cortex-A720_AE, the following errata build flags are defined :
 
 -  ``ERRATA_A720_AE_3699562``: This applies errata 3699562 workaround
-   to Cortex-A715_AE CPU. This needs to be enabled for revisions r0p0.
+   to Cortex-A720_AE CPU. This needs to be enabled for revisions r0p0.
    It is still open.
 
 For Cortex-A725, the following errata build flags are defined :
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
index 2ba54ea..cf8cbc7 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -247,7 +247,7 @@
 
 -  CPU initialization
 
-   BL1 calls the ``reset_handler()`` function which in turn calls the CPU
+   BL1 calls the ``reset_handler`` macro/function which in turn calls the CPU
    specific reset handler function (see the section: "CPU specific operations
    framework").
 
@@ -1337,7 +1337,7 @@
 
 TF-A implements a framework that allows CPU and platform ports to perform
 actions very early after a CPU is released from reset in both the cold and warm
-boot paths. This is done by calling the ``reset_handler()`` function in both
+boot paths. This is done by calling the ``reset_handler`` macro/function in both
 the BL1 and BL31 images. It in turn calls the platform and CPU specific reset
 handling functions.
 
@@ -1481,7 +1481,9 @@
 handling for that CPU and also any errata workarounds enabled by the platform.
 
 It should be defined using the ``cpu_reset_func_{start,end}`` macros and its
-body may only clobber x0 to x14 with x14 being the cpu_rev parameter.
+body may only clobber x0 to x14 with x14 being the cpu_rev parameter. The cpu
+file should also include a call to ``cpu_reset_prologue`` at the start of the
+file for errata to work correctly.
 
 CPU specific power down sequence
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1504,6 +1506,19 @@
 perform platform specific operations during a power down sequence, for example
 turning off CCI coherency during a cluster power down.
 
+Newer CPUs include a feature called "powerdown abandon". The feature is based on
+the observation that events like GIC wakeups have a high likelihood of happening
+while the core is in the middle of its powerdown sequence (at ``wfi``). Older
+cores will powerdown and immediately power back up when this happens. To save on
+the work and latency involved, the newer cores will "give up" mid way through if
+no context has been lost yet. This is possible as the powerdown operation is
+lengthy and a large part of it does not lose context.
+
+To cater for this possibility, the powerdown hook will be called a second time
+after a wakeup. The expectation is that the first call will operate as before,
+while the second call will undo anything the first call did. This should be done
+statelessly, for example by toggling the relevant bits.
+
 CPU specific register reporting during crash
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2891,7 +2906,7 @@
 
 --------------
 
-*Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.*
 
 .. _SMCCC: https://developer.arm.com/docs/den0028/latest
 .. _PSCI: https://developer.arm.com/documentation/den0022/latest/
diff --git a/docs/design/index.rst b/docs/design/index.rst
index 17ef756..f0ca540 100644
--- a/docs/design/index.rst
+++ b/docs/design/index.rst
@@ -12,9 +12,10 @@
    interrupt-framework-design
    psci-pd-tree
    reset-design
+   console-framework
    trusted-board-boot
    trusted-board-boot-build
 
 --------------
 
-*Copyright (c) 2019, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2025, Arm Limited. All rights reserved.*
diff --git a/docs/design_documents/rse.rst b/docs/design_documents/rse.rst
index 21e5fd4..d1a5b9e 100644
--- a/docs/design_documents/rse.rst
+++ b/docs/design_documents/rse.rst
@@ -25,9 +25,15 @@
 -----------------------
 
 The communication between RSE and other subsystems are primarily relying on the
-Message Handling Unit (MHU) module. The number of MHU interfaces between RSE
-and other cores is IMPDEF. Besides MHU other modules also could take part in
-the communication. RSE is capable of mapping the AP memory to its address space.
+Message Handling Unit (MHU) module.
+
+However, this is possible to use this communication protocol with a different
+mailbox than MHU, by setting the flag ``PLAT_MHU=NO_MHU`` and implementing the
+APIs given in the file: ``include/drivers/arm/rse_comms.h``.
+
+The number of MHU interfaces between RSE and other cores is IMPDEF. Besides MHU
+other modules also could take part in the communication. RSE is capable of
+mapping the AP memory to its address space.
 Thereby either RSE core itself or a DMA engine if it is present, can move the
 data between memory belonging to RSE or AP. In this way, a bigger amount of data
 can be transferred in a short time.
@@ -812,3 +818,4 @@
 
 *Copyright (c) 2023-2024, Arm Limited. All rights reserved.*
 *Copyright (c) 2024, Linaro Limited. All rights reserved.*
+*Copyright (c) 2025, STMicroelectronics - All Rights Reserved*
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 5b83448..2b36fda 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -258,10 +258,6 @@
    (also known as group 1 counters). These are implementation-defined counters,
    and as such require additional platform configuration. Default is 0.
 
--  ``ENABLE_AMU_FCONF``: Enables configuration of the AMU through FCONF, which
-   allows platforms with auxiliary counters to describe them via the
-   ``HW_CONFIG`` device tree blob. Default is 0.
-
 -  ``ENABLE_ASSERTIONS``: This option controls whether or not calls to ``assert()``
    are compiled out. For debug builds, this option defaults to 1, and calls to
    ``assert()`` are left in place. For release builds, this option defaults to 0
@@ -526,9 +522,11 @@
    power domain dynamic power budgeting and limit the triggering of whole-rail
    (i.e. clock chopping) responses to overcurrent conditions. Defaults to ``0``.
 
--  ``ENABLE_MPMM_FCONF``: Enables configuration of MPMM through FCONF, which
-   allows platforms with cores supporting MPMM to describe them via the
-   ``HW_CONFIG`` device tree blob. Default is 0.
+ - ``FEAT_PABANDON``: Boolean option to enable support for powerdown abandon on
+   Arm cores that support it (currently Gelas and Travis). Extends the PSCI
+   implementation to expect waking up after the terminal ``wfi``. Currently,
+   introduces a performance penalty. Once this is removed, this option will be
+   removed and the feature will be enabled by default. Defaults to ``0``.
 
 -  ``ENABLE_PIE``: Boolean option to enable Position Independent Executable(PIE)
    support within generic code in TF-A. This option is currently only supported
@@ -1206,6 +1204,12 @@
       implement this workaround due to the behaviour of the errata mentioned
       in new SDEN document which will get published soon.
 
+- ``ERRATA_SME_POWER_DOWN``: Boolean option to disable SME (PSTATE.{ZA,SM}=0)
+  before power down and downgrade a suspend to power down request to a normal
+  suspend request. This is necessary when software running at lower ELs requests
+  power down without first clearing these bits. On affected cores, the CME
+  connected to it will reject its power down request. The default value is 0.
+
 - ``RAS_TRAP_NS_ERR_REC_ACCESS``: This flag enables/disables the SCR_EL3.TERR
   bit, to trap access to the RAS ERR and RAS ERX registers from lower ELs.
   This flag is disabled by default.
diff --git a/docs/plat/arm/arm-build-options.rst b/docs/plat/arm/arm-build-options.rst
index a086a98..3fad566 100644
--- a/docs/plat/arm/arm-build-options.rst
+++ b/docs/plat/arm/arm-build-options.rst
@@ -137,7 +137,8 @@
 ---------------------
 
 - ``FVP_TRUSTED_SRAM_SIZE``: Size (in kilobytes) of the Trusted SRAM region to
-  utilize when building for the FVP platform. This option defaults to 256.
+  utilize when building for the FVP platform. This option defaults to 256 with
+  build option ENABLE_RME=0 and 384 for ENABLE_RME=1.
 
 Arm Juno Build Options
 ----------------------
diff --git a/docs/plat/arm/fvp/fvp-build-options.rst b/docs/plat/arm/fvp/fvp-build-options.rst
index b0359fa..79dc0dc 100644
--- a/docs/plat/arm/fvp/fvp-build-options.rst
+++ b/docs/plat/arm/fvp/fvp-build-options.rst
@@ -46,6 +46,16 @@
    is ``0``, which means the redistributor pages of all CPU cores are marked
    as read and write.
 
+-  ``INITRD_SIZE`` : Enable the insertion of initrd properties to the device
+   tree blob at build time. Takes an initrd size value in hex format
+
+-  ``INITRD_PATH`` : Enable the insertion of initrd properties to the device tree
+   blob at build time. Takes a path to an initrd file. Can be used as an
+   alternative to ``INITRD_SIZE``. ``INITRD_SIZE`` takes precedence over
+   ``INITRD_PATH`` if both values are provided.
+
+-  ``INITRD_BASE`` : Provide the preloaded initrd base address in memory (hex format).
+
 --------------
 
-*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2025, Arm Limited. All rights reserved.*
diff --git a/docs/plat/arm/fvp/fvp-specific-configs.rst b/docs/plat/arm/fvp/fvp-specific-configs.rst
index 63b3c31..0f51e4b 100644
--- a/docs/plat/arm/fvp/fvp-specific-configs.rst
+++ b/docs/plat/arm/fvp/fvp-specific-configs.rst
@@ -73,85 +73,122 @@
    The address provided to the FVP must match the ``EL3_PAYLOAD_BASE`` address
    used when building TF-A.
 
-Booting a preloaded kernel image (Base FVP)
--------------------------------------------
+Booting a kernel image in BL33
+------------------------------
 
-The following example uses a simplified boot flow by directly jumping from the
-TF-A to the Linux kernel, which will use a ramdisk as filesystem. This can be
-useful if both the kernel and the device tree blob (DTB) are already present in
-memory (like in FVP).
+TF-A can boot a Linux kernel, which uses a ramdisk as a filesystem. The
+required initrd properties are injected in to the device tree blob (DTB) at
+build time.
 
-For example, if the kernel is loaded at ``0x80080000`` and the DTB is loaded at
-address ``0x82000000``, the firmware can be built like this:
+Kernel image packaged in fip as a BL33 image
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A Linux kernel image can be packaged in the fip as a BL33 image and then
+booted in TF-A.
+
+For example, the firmware can be built as:
 
 .. code:: shell
 
-    CROSS_COMPILE=aarch64-none-elf-  \
     make PLAT=fvp DEBUG=1             \
-    RESET_TO_BL31=1                   \
-    ARM_LINUX_KERNEL_AS_BL33=1        \
-    PRELOADED_BL33_BASE=0x80080000    \
-    ARM_PRELOADED_DTB_BASE=0x82000000 \
+    ARM_LINUX_KERNEL_AS_BL33          \
+    BL33=<path-to-kernel-binary>      \
+    INITRD_SIZE=0x8000000             \
     all fip
 
+The options ``INITRD_SIZE`` or ``INITRD_PATH`` triggers the insertion of initrd
+properties in to the DTB. ``INITRD_BASE`` is also required but a default value
+is set by the FVP platform.
+
+The options available here are:
+
+::
+
-Now, it is needed to modify the DTB so that the kernel knows the address of the
-ramdisk. The following script generates a patched DTB from the provided one,
-assuming that the ramdisk is loaded at address ``0x84000000``. Note that this
-script assumes that the user is using a ramdisk image prepared for U-Boot, like
-the ones provided by Linaro. If using a ramdisk without this header,the ``0x40``
-offset in ``INITRD_START`` has to be removed.
+    INITRD_BASE: Set the initrd base address in memory. Defaults to 0x90000000 in FVP.
+    INITRD_SIZE: Set the initrd size in dec or hex format. Hex format must precede with '0x'.
+    INITRD_PATH: Provide an initrd path for the build time to determine its exact size.
 
-.. code:: bash
+Users can provide either ``INITRD_SIZE`` or ``INITRD_PATH`` to set the initrd
+size value. ``INITRD_SIZE`` takes prioty over ``INITRD_PATH``.
 
-    #!/bin/bash
+Now the fvp binary can be run as:
 
-    # Path to the input DTB
-    KERNEL_DTB=<path-to>/<fdt>
-    # Path to the output DTB
-    PATCHED_KERNEL_DTB=<path-to>/<patched-fdt>
-    # Base address of the ramdisk
-    INITRD_BASE=0x84000000
-    # Path to the ramdisk
-    INITRD=<path-to>/<ramdisk.img>
+.. code:: shell
+
+    <path-to>/FVP_Base_AEMv8A-AEMv8A                            \
+    -C bp.secureflashloader.fname=<path-to>/bl1.bin             \
+    -C bp.flashloader0.fname=<path-to>/fip.bin                  \
+    --data cluster0.cpu0="<path-to>/<initrd.bin>"@0x90000000
+
+.. note::
+    Providing a higher value for an initrd size than the actual size of the file
+    is supported but it will trigger a non-breaking "Initramfs unpacking failed"
+    error by the kernel at runtime. This error can be ignored because initrd's
+    can be stacked one after another, when the kernel unpacks the first initrd it
+    looks for another in the extra space which it won't find, hence the error.
 
-    # Skip uboot header (64 bytes)
-    INITRD_START=$(printf "0x%x" $((${INITRD_BASE} + 0x40)) )
-    INITRD_SIZE=$(stat -Lc %s ${INITRD})
-    INITRD_END=$(printf "0x%x" $((${INITRD_BASE} + ${INITRD_SIZE})) )
+Preloaded kernel image - Normal flow
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-    CHOSEN_NODE=$(echo                                        \
-    "/ {                                                      \
-            chosen {                                          \
-                    linux,initrd-start = <${INITRD_START}>;   \
-                    linux,initrd-end = <${INITRD_END}>;       \
-            };                                                \
-    };")
+The following example uses a simplified boot flow to boot a Linux kernel
+using TF-A. This can be useful if the kernel is already present in memory
+(like in FVP).
+
+For example, if the kernel is loaded at ``0x80080000`` the firmware can be
+built like this:
+
+.. code:: shell
 
-    echo $(dtc -O dts -I dtb ${KERNEL_DTB}) ${CHOSEN_NODE} |  \
-            dtc -O dtb -o ${PATCHED_KERNEL_DTB} -
+    make PLAT=fvp DEBUG=1             \
+    ARM_LINUX_KERNEL_AS_BL33=1        \
+    PRELOADED_BL33_BASE=0x80080000    \
+    INITRD_SIZE=0x8000000             \
+    all fip
 
-And the FVP binary can be run with the following command:
+Now the FVP binary can be run with the following command:
 
 .. code:: shell
 
     <path-to>/FVP_Base_AEMv8A-AEMv8A                            \
-    -C pctl.startup=0.0.0.0                                     \
-    -C bp.secure_memory=1                                       \
-    -C cluster0.NUM_CORES=4                                     \
-    -C cluster1.NUM_CORES=4                                     \
-    -C cache_state_modelled=1                                   \
-    -C cluster0.cpu0.RVBAR=0x04001000                           \
-    -C cluster0.cpu1.RVBAR=0x04001000                           \
-    -C cluster0.cpu2.RVBAR=0x04001000                           \
-    -C cluster0.cpu3.RVBAR=0x04001000                           \
-    -C cluster1.cpu0.RVBAR=0x04001000                           \
-    -C cluster1.cpu1.RVBAR=0x04001000                           \
-    -C cluster1.cpu2.RVBAR=0x04001000                           \
-    -C cluster1.cpu3.RVBAR=0x04001000                           \
-    --data cluster0.cpu0="<path-to>/bl31.bin"@0x04001000        \
-    --data cluster0.cpu0="<path-to>/<patched-fdt>"@0x82000000   \
+    -C bp.secureflashloader.fname=<path-to>/bl1.bin             \
+    -C bp.flashloader0.fname=<path-to>/fip.bin                  \
     --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
-    --data cluster0.cpu0="<path-to>/<ramdisk.img>"@0x84000000
+    --data cluster0.cpu0="<path-to>/<initrd.bin>"@0x90000000
+
+Preloaded kernel image - Reset to BL31
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We can also boot a Linux kernel by jumping directly to BL31 ``RESET_TO_BL31=1``.
+This requires preloading a DTB into memory. We can inject the initrd start and
+end properties into the DTB (HW_CONFIG) at build time which is then stored by
+TF-A in ``build/fvp/<build-type>/fdts/`` directory.
+
+For example, we can build the firmware as:
+
+.. code:: shell
+
+    make PLAT=fvp DEBUG=1                   \
+    RESET_TO_BL31=1                         \
+    ARM_LINUX_KERNEL_AS_BL33=1              \
+    PRELOADED_BL33_BASE=0x80080000          \
+    ARM_PRELOADED_DTB_BASE=0x87F00000       \
+    INITRD_BASE=0x88000000                  \
+    INITRD_PATH=<path-to>/initrd.bin
+
+Now we can run the binary as:
+
+.. code:: shell
+
+    <path-to>/FVP_Base_AEMv8A-AEMv8A                               \
+    -C cluster0.NUM_CORES=4                                        \
+    -C cluster0.cpu0.RVBAR=0x04001000                              \
+    -C cluster0.cpu1.RVBAR=0x04001000                              \
+    -C cluster0.cpu2.RVBAR=0x04001000                              \
+    -C cluster0.cpu3.RVBAR=0x04001000                              \
+    --data cluster0.cpu0="<path-to>/bl31.bin"@0x04001000           \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000    \
+    --data cluster0.cpu0="<path-to>/<initrd.bin>"@0x88000000       \
+    --data cluster0.cpu0="<path-to>/fdts/fvp-base-gicv3-psci.dtb"@87F00000
 
 Obtaining the Flattened Device Trees
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/docs/plat/arm/fvp/fvp-support.rst b/docs/plat/arm/fvp/fvp-support.rst
index ad76cf1..0ce1905 100644
--- a/docs/plat/arm/fvp/fvp-support.rst
+++ b/docs/plat/arm/fvp/fvp-support.rst
@@ -9,24 +9,22 @@
 (64-bit host machine only).
 
 .. note::
-   The FVP models used are Version 11.26 Build 11, unless otherwise stated.
+   The FVP models used are version 11.28 Build 23.
 
 -  ``FVP_Base_AEMvA-AEMvA``
 -  ``FVP_Base_RevC-2xAEMvA``
--  ``FVP_Base_Cortex-A32x4``
--  ``FVP_Base_Cortex-A35x4``
--  ``FVP_Base_Cortex-A53x4``
+-  ``FVP_Base_Cortex-A32``
+-  ``FVP_Base_Cortex-A35``
+-  ``FVP_Base_Cortex-A53``
 -  ``FVP_Base_Cortex-A55``
 -  ``FVP_Base_Cortex-A57x1-A53x1``
 -  ``FVP_Base_Cortex-A57x2-A53x4``
--  ``FVP_Base_Cortex-A57x4``
+-  ``FVP_Base_Cortex-A57``
 -  ``FVP_Base_Cortex-A57x4-A53x4``
--  ``FVP_Base_Cortex-A65`` (Version 11.24/24)
--  ``FVP_Base_Cortex-A65AE`` (Version 11.24/24)
--  ``FVP_Base_Cortex-A710``
--  ``FVP_Base_Cortex-A72x4``
--  ``FVP_Base_Cortex-A72x4-A53x4``
--  ``FVP_Base_Cortex-A73x4``
+-  ``FVP_Base_Cortex-A65``
+-  ``FVP_Base_Cortex-A65AE``
+-  ``FVP_Base_Cortex-A72``
+-  ``FVP_Base_Cortex-A73``
 -  ``FVP_Base_Cortex-A73x4-A53x4``
 -  ``FVP_Base_Cortex-A75``
 -  ``FVP_Base_Cortex-A76``
@@ -35,17 +33,17 @@
 -  ``FVP_Base_Cortex-A78``
 -  ``FVP_Base_Cortex-A78AE``
 -  ``FVP_Base_Cortex-A78C``
+-  ``FVP_Base_Cortex-A710``
 -  ``FVP_Base_Cortex-X2``
--  ``FVP_Base_Neoverse-E1`` (Version 11.24/24)
+-  ``FVP_Base_Cortex-X4``
+-  ``FVP_Base_Cortex-X925``
+-  ``FVP_Base_Neoverse-E1``
 -  ``FVP_Base_Neoverse-N1``
 -  ``FVP_Base_Neoverse-N2``
 -  ``FVP_Base_Neoverse-V1``
 -  ``FVP_BaseR_AEMv8R``
--  ``FVP_Morello`` (Version 0.11/33)
--  ``FVP_RD_V1``
--  ``FVP_RD_1_AE`` (Version 11.27/20)
--  ``FVP_TC3`` (Version 11.26/16)
--  ``FVP_TC4`` (Version 0.0/8404)
+-  ``FVP_RD_1_AE``
+-  ``FVP_TC4``
 
 The latest version of the AArch32 build of TF-A has been tested on the
 following Arm FVPs without shifted affinities, and that do not support threaded
@@ -53,7 +51,7 @@
 
 -  ``FVP_Base_AEMvA``
 -  ``FVP_Base_AEMvA-AEMvA``
--  ``FVP_Base_Cortex-A32x4``
+-  ``FVP_Base_Cortex-A32``
 
 .. note::
    The ``FVP_Base_RevC-2xAEMv8A`` FVP only supports shifted affinities, which
@@ -94,7 +92,7 @@
 
 --------------
 
-*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2025, Arm Limited. All rights reserved.*
 
 .. _Arm's website: `FVP models`_
 .. _FVP models: https://developer.arm.com/products/system-design/fixed-virtual-platforms
diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst
index 384cd73..016bed7 100644
--- a/docs/plat/rockchip.rst
+++ b/docs/plat/rockchip.rst
@@ -11,6 +11,7 @@
 -  rk3368: Octa-Core Cortex-A53
 -  rk3399: Hexa-Core Cortex-A53/A72
 -  rk3566/rk3568: Quad-Core Cortex-A55
+-  rk3576: Octa-Core Cortex-A53/A72
 -  rk3588: Octa-Core Cortex-A55/A76
 
 
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 6d03f44..0f0dedd 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -1001,7 +1001,7 @@
 This function returns the size normal-world DCE of the platform.
 
 Function : plat_drtm_get_imp_def_dlme_region_size()
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 ::
 
@@ -1012,7 +1012,7 @@
 of the platform.
 
 Function : plat_drtm_get_tcb_hash_table_size()
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 ::
 
@@ -1021,8 +1021,18 @@
 
 This function returns the size of TCB hash table of the platform.
 
+Function : plat_drtm_get_acpi_tables_region_size()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint64_t
+
+This function returns the size of ACPI tables region of the platform.
+
 Function : plat_drtm_get_tcb_hash_features()
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 ::
 
@@ -1033,6 +1043,17 @@
 platform.
 For more details see section 3.3 Table 6 of `DRTM`_ specification.
 
+Function : plat_drtm_get_dlme_img_auth_features()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint64_t
+
+This function returns the DLME image authentication features.
+For more details see section 3.3 Table 6 of `DRTM`_ specification.
+
 Function : plat_drtm_validate_ns_region()
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2220,10 +2241,10 @@
     Argument : void
     Return   : void
 
-The purpose of this function is allow the platform to perform any BL31 runtime
-setup just prior to BL31 exit during cold boot. The default weak
-implementation of this function will invoke ``console_switch_state()`` to switch
-console output to consoles marked for use in the ``runtime`` state.
+The purpose of this function is to allow the platform to perform any BL31 runtime
+setup just prior to BL31 exit during cold boot. The default weak implementation
+of this function is empty. Any platform that needs to perform additional runtime
+setup, before BL31 exits, will need to override this function.
 
 Function : bl31_plat_get_next_image_ep_info() [mandatory]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2897,23 +2918,27 @@
 data, for example in DRAM. The Distributor can then be powered down using an
 implementation-defined sequence.
 
-plat_psci_ops.pwr_domain_pwr_down_wfi()
+plat_psci_ops.pwr_domain_pwr_down()
 .......................................
 
 This is an optional function and, if implemented, is expected to perform
-platform specific actions including the ``wfi`` invocation which allows the
-CPU to powerdown. Since this function is invoked outside the PSCI locks,
-the actions performed in this hook must be local to the CPU or the platform
-must ensure that races between multiple CPUs cannot occur.
+platform specific actions before the CPU is powered down. Since this function is
+invoked outside the PSCI locks, the actions performed in this hook must be local
+to the CPU or the platform must ensure that races between multiple CPUs cannot
+occur.
 
 The ``target_state`` has a similar meaning as described in the ``pwr_domain_off()``
 operation and it encodes the platform coordinated target local power states for
-the CPU power domain and its parent power domain levels. This function must
-not return back to the caller (by calling wfi in an infinite loop to ensure
-some CPUs power down mitigations work properly).
+the CPU power domain and its parent power domain levels.
 
-If this function is not implemented by the platform, PSCI generic
-implementation invokes ``psci_power_down_wfi()`` for power down.
+It is preferred that this function returns. The caller will invoke
+``psci_power_down_wfi()`` to powerdown the CPU, mitigate any powerdown errata,
+and handle any wakeups that may arise. Previously, this function did not return
+and instead called ``wfi`` (in an infinite loop) directly. This is still
+possible on platforms where this is guaranteed to be terminal, however, it is
+strongly discouraged going forward.
+
+Previously this function was called ``pwr_domain_pwr_down_wfi()``.
 
 plat_psci_ops.pwr_domain_on_finish()
 ....................................
@@ -2965,14 +2990,16 @@
 
 This function is called by PSCI implementation in response to a ``SYSTEM_OFF``
 call. It performs the platform-specific system poweroff sequence after
-notifying the Secure Payload Dispatcher.
+notifying the Secure Payload Dispatcher. The caller will call ``wfi`` if this
+function returns, similar to `plat_psci_ops.pwr_domain_pwr_down()`_.
 
 plat_psci_ops.system_reset()
 ............................
 
 This function is called by PSCI implementation in response to a ``SYSTEM_RESET``
 call. It performs the platform-specific system reset sequence after
-notifying the Secure Payload Dispatcher.
+notifying the Secure Payload Dispatcher. The caller will call ``wfi`` if this
+function returns, similar to `plat_psci_ops.pwr_domain_pwr_down()`_.
 
 plat_psci_ops.validate_power_state()
 ....................................
@@ -3060,7 +3087,8 @@
 function must return ``PSCI_E_NOT_SUPPORTED``. For architectural
 resets, all failures must return ``PSCI_E_INVALID_PARAMETERS``
 and vendor reset can return other PSCI error codes as defined
-in `PSCI`_. On success this function will not return.
+in `PSCI`_. If this function returns success, the caller will call
+``wfi`` similar to `plat_psci_ops.pwr_domain_pwr_down()`_.
 
 plat_psci_ops.write_mem_protect()
 .................................
@@ -3296,6 +3324,21 @@
 (``GICD_IGRPMODRn``) is read to figure out whether the interrupt is configured
 as Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt.
 
+Registering a console
+---------------------
+
+Platforms will need to implement the TF-A console framework to register and use
+a console for visual data output in TF-A. These can be used for data output during
+the different stages of the firmware boot process and also for debugging purposes.
+
+The console framework can be used to output data on to a console using a number of
+TF-A supported UARTs. Multiple consoles can be registered at the same time with
+different output scopes (BOOT, RUNTIME, CRASH) so that data can be displayed on
+their respective consoles without unnecessary cluttering of a single console.
+
+Information for registering a console can be found in the :ref:`Console Framework` section
+of the :ref:`System Design` documentation.
+
 Common helper functions
 -----------------------
 Function : elx_panic()
@@ -3416,6 +3459,18 @@
 External Abort handling and RAS Support
 ---------------------------------------
 
+If any cores on the platform support powerdown abandon (i.e. ``FEAT_PABANDON``
+is set, check the "Core powerup and powerdown sequence" in their TRMs), then
+these functions should be able to handle being called with power domains off and
+after the powerdown ``wfi``. In other words it may run after a call to
+``pwr_domain_suspend()`` and before a call to ``pwr_domain_suspend_finish()``
+(and their power off counterparts).
+
+Should this not be desirable, or if there is no powerdown abandon support, then
+RAS errors should be masked by writing any relevant error records in any
+powerdown hooks to prevent deadlocks due to a RAS error after the point of no
+return. See the core's TRM for further information.
+
 Function : plat_ea_handler
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -3700,7 +3755,7 @@
 
 --------------
 
-*Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.*
 
 .. _PSCI: https://developer.arm.com/documentation/den0022/latest/
 .. _Arm Generic Interrupt Controller version 2.0 (GICv2): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0048b/index.html
diff --git a/docs/tools/memory-layout-tool.rst b/docs/tools/memory-layout-tool.rst
index 8874bd7..d9c358d 100644
--- a/docs/tools/memory-layout-tool.rst
+++ b/docs/tools/memory-layout-tool.rst
@@ -23,7 +23,7 @@
 
     .. code:: shell
 
-        poetry install --with memory
+        poetry install --no-root
 
 #. Verify that the tool runs in the installed virtual environment
 
@@ -231,6 +231,6 @@
 
 --------------
 
-*Copyright (c) 2023, Arm Limited. All rights reserved.*
+*Copyright (c) 2023-2025, Arm Limited. All rights reserved.*
 
 .. _Poetry: https://python-poetry.org/docs/
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
index fbcbdc7..b310ff4 100644
--- a/drivers/arm/css/scp/css_pm_scmi.c
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -298,7 +298,7 @@
 #endif
 }
 
-void __dead2 css_scp_system_off(int state)
+void css_scp_system_off(int state)
 {
 	int ret;
 
@@ -339,16 +339,13 @@
 	}
 
 	/* Powerdown of primary core */
-	psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
-	wfi();
-	ERROR("CSS set power state: operation not handled.\n");
-	panic();
+	psci_pwrdown_cpu_start(PLAT_MAX_PWR_LVL);
 }
 
 /*
  * Helper function to shutdown the system via SCMI.
  */
-void __dead2 css_scp_sys_shutdown(void)
+void css_scp_sys_shutdown(void)
 {
 	css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
 }
@@ -356,7 +353,7 @@
 /*
  * Helper function to reset the system via SCMI.
  */
-void __dead2 css_scp_sys_reboot(void)
+void css_scp_sys_reboot(void)
 {
 	css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
 }
@@ -472,12 +469,8 @@
 		return PSCI_E_INVALID_PARAMS;
 
 	css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
-	/*
-	 * css_scp_system_off cannot return (it is a __dead function),
-	 * but css_system_reset2 has to return some value, even in
-	 * this case.
-	 */
-	return 0;
+	/* return SUCCESS to finish the powerdown */
+	return PSCI_E_SUCCESS;
 }
 
 #if PROGRAMMABLE_RESET_ADDRESS
diff --git a/drivers/arm/css/scp/css_pm_scpi.c b/drivers/arm/css/scp/css_pm_scpi.c
index b4019ce..02be070 100644
--- a/drivers/arm/css/scp/css_pm_scpi.c
+++ b/drivers/arm/css/scp/css_pm_scpi.c
@@ -117,7 +117,7 @@
 /*
  * Helper function to shutdown the system via SCPI.
  */
-void __dead2 css_scp_sys_shutdown(void)
+void css_scp_sys_shutdown(void)
 {
 	uint32_t response;
 
@@ -134,15 +134,12 @@
 		ERROR("CSS System Off: SCP error %u.\n", response);
 		panic();
 	}
-	wfi();
-	ERROR("CSS System Off: operation not handled.\n");
-	panic();
 }
 
 /*
  * Helper function to reset the system via SCPI.
  */
-void __dead2 css_scp_sys_reboot(void)
+void css_scp_sys_reboot(void)
 {
 	uint32_t response;
 
@@ -159,7 +156,4 @@
 		ERROR("CSS System Reset: SCP error %u.\n", response);
 		panic();
 	}
-	wfi();
-	ERROR("CSS System Reset: operation not handled.\n");
-	panic();
 }
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
index 5e44aa9..6e9567e 100644
--- a/drivers/arm/gic/v3/gic600_multichip.c
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -322,12 +322,40 @@
 }
 
 /*******************************************************************************
+ * Initialize GIC-600 and GIC-700 Multichip operation in LCA mode by setting up
+ * the routing table first.
+ ******************************************************************************/
+static void gic600_multichip_lca_init(
+		struct gic600_multichip_data *multichip_data)
+{
+	unsigned int i, j;
+	unsigned int rt_owner = multichip_data->rt_owner;
+
+	for (i = 0; i < multichip_data->chip_count; i++) {
+		for (j = 0; j < multichip_data->chip_count; j++) {
+			INFO("RT(LCA): CHIP%u -> CHIP%u 0x%lx\n", i, j,
+					multichip_data->chip_addrs[i][j]);
+			set_gicd_chipr_n(multichip_data->base_addrs[i], j,
+				multichip_data->chip_addrs[i][j],
+				multichip_data->spi_ids[j].spi_id_min,
+				multichip_data->spi_ids[j].spi_id_max);
+		}
+	}
+
+	/* Initialize the GICD which is marked as routing table owner last */
+	set_gicd_dchipr_rt_owner(multichip_data->base_addrs[rt_owner],
+			rt_owner);
+}
+
+/*******************************************************************************
  * Initialize GIC-600 and GIC-700 Multichip operation.
  ******************************************************************************/
 void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
 {
 	unsigned int i;
-	uint32_t gicd_iidr_val = gicd_read_iidr(multichip_data->rt_owner_base);
+	unsigned int rt_owner = multichip_data->rt_owner;
+	uint32_t gicd_iidr_val =
+			gicd_read_iidr(multichip_data->base_addrs[rt_owner]);
 
 	if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) {
 		gic600_multichip_validate_data(multichip_data);
@@ -341,16 +369,16 @@
 	 * Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
 	 * that GIC-600 Multichip configuration is done first.
 	 */
-	if ((gicd_read_ctlr(multichip_data->rt_owner_base) &
-			(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
-			 CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+	if ((gicd_read_ctlr(multichip_data->base_addrs[rt_owner]) &
+		 (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+		  CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
 		ERROR("GICD_CTLR group interrupts are either enabled or have "
 				"pending writes.\n");
 		panic();
 	}
 
 	/* Ensure that the routing table owner is in disconnected state */
-	if (((read_gicd_chipsr(multichip_data->rt_owner_base) &
+	if (((read_gicd_chipsr(multichip_data->base_addrs[rt_owner]) &
 		GICD_CHIPSR_RTS_MASK) >> GICD_CHIPSR_RTS_SHIFT) !=
 			GICD_CHIPSR_RTS_STATE_DISCONNECTED) {
 		ERROR("GIC-600 routing table owner is not in disconnected "
@@ -358,25 +386,34 @@
 		panic();
 	}
 
-	/* Initialize the GICD which is marked as routing table owner first */
-	set_gicd_dchipr_rt_owner(multichip_data->rt_owner_base,
-			multichip_data->rt_owner);
+	/* If LCA is not enabled */
+	if ((read_gicd_cfgid(multichip_data->base_addrs[rt_owner]) &
+			GICD_CFGID_LCA_BIT) == 0) {
+		/*
+		 * Initialize the GICD which is marked as routing table
+		 * owner first.
+		 */
+		set_gicd_dchipr_rt_owner(multichip_data->base_addrs[rt_owner],
+			rt_owner);
 
-	set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
-			multichip_data->chip_addrs[multichip_data->rt_owner],
-			multichip_data->
-			spi_ids[multichip_data->rt_owner].spi_id_min,
-			multichip_data->
-			spi_ids[multichip_data->rt_owner].spi_id_max);
+		set_gicd_chipr_n(multichip_data->base_addrs[rt_owner], rt_owner,
+			multichip_data->chip_addrs[rt_owner][rt_owner],
+			multichip_data->spi_ids[rt_owner].spi_id_min,
+			multichip_data->spi_ids[rt_owner].spi_id_max);
 
-	for (i = 0; i < multichip_data->chip_count; i++) {
-		if (i == multichip_data->rt_owner)
-			continue;
-
-		set_gicd_chipr_n(multichip_data->rt_owner_base, i,
-				multichip_data->chip_addrs[i],
+		for (i = 0; i < multichip_data->chip_count; i++) {
+			if (i == rt_owner)
+				continue;
+			set_gicd_chipr_n(
+				multichip_data->base_addrs[rt_owner], i,
+				multichip_data->chip_addrs[rt_owner][i],
 				multichip_data->spi_ids[i].spi_id_min,
 				multichip_data->spi_ids[i].spi_id_max);
+		}
+	} else {
+		/* If LCA is enabled */
+		INFO("GIC Local chip addressing is enabled\n");
+		gic600_multichip_lca_init(multichip_data);
 	}
 
 	plat_gic_multichip_data = multichip_data;
diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h
index fd1cb57..33030b3 100644
--- a/drivers/arm/gic/v3/gic600_multichip_private.h
+++ b/drivers/arm/gic/v3/gic600_multichip_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2023, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,12 +15,14 @@
 #define GICD_CHIPSR			U(0xC000)
 #define GICD_DCHIPR			U(0xC004)
 #define GICD_CHIPR			U(0xC008)
+#define GICD_CFGID			U(0xF000)
 
 /* GIC600 GICD multichip related masks */
 #define GICD_CHIPRx_PUP_BIT		BIT_64(1)
 #define GICD_CHIPRx_SOCKET_STATE	BIT_64(0)
 #define GICD_DCHIPR_PUP_BIT		BIT_32(0)
 #define GICD_CHIPSR_RTS_MASK		(BIT_32(4) | BIT_32(5))
+#define GICD_CFGID_LCA_BIT		BIT_64(21)
 
 /* GIC600 GICD multichip related shifts */
 #define GICD_CHIPRx_ADDR_SHIFT		16
@@ -98,6 +100,11 @@
 	return mmio_read_32(base + GICD_CHIPSR);
 }
 
+static inline uint64_t read_gicd_cfgid(uintptr_t base)
+{
+	return mmio_read_64(base + GICD_CFGID);
+}
+
 static inline void write_gicd_dchipr(uintptr_t base, uint32_t val)
 {
 	mmio_write_32(base + GICD_DCHIPR, val);
diff --git a/drivers/arm/rse/rse_comms.c b/drivers/arm/rse/rse_comms.c
index cfc5a83..48023bc 100644
--- a/drivers/arm/rse/rse_comms.c
+++ b/drivers/arm/rse/rse_comms.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,7 +8,6 @@
 #include <string.h>
 
 #include <common/debug.h>
-#include <drivers/arm/mhu.h>
 #include <drivers/arm/rse_comms.h>
 #include <psa/client.h>
 #include <rse_comms_protocol.h>
@@ -24,7 +23,7 @@
 static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
 				       const psa_outvec *out_vec, size_t out_len)
 {
-	size_t comms_mhu_msg_size;
+	size_t comms_mbx_msg_size;
 	size_t comms_embed_msg_min_size;
 	size_t comms_embed_reply_min_size;
 	size_t in_size_total = 0;
@@ -38,7 +37,7 @@
 		out_size_total += out_vec[i].len;
 	}
 
-	comms_mhu_msg_size = mhu_get_max_message_size();
+	comms_mbx_msg_size = rse_mbx_get_max_message_size();
 
 	comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) +
 				   sizeof(struct rse_embed_msg_t) -
@@ -49,9 +48,9 @@
 				     PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
 
 	/* Use embed if we can pack into one message and reply, else use
-	 * pointer_access. The underlying MHU transport protocol uses a
+	 * pointer_access. The underlying mailbox transport protocol uses a
 	 * single uint32_t to track the length, so the amount of data that
-	 * can be in a message is 4 bytes less than mhu_get_max_message_size
+	 * can be in a message is 4 bytes less than rse_mbx_get_max_message_size
 	 * reports.
 	 *
 	 * TODO tune this with real performance numbers, it's possible a
@@ -60,9 +59,9 @@
 	 * pointers.
 	 */
 	if ((comms_embed_msg_min_size + in_size_total >
-	     comms_mhu_msg_size - sizeof(uint32_t)) ||
+	     comms_mbx_msg_size - sizeof(uint32_t)) ||
 	    (comms_embed_reply_min_size + out_size_total >
-	     comms_mhu_msg_size - sizeof(uint32_t))) {
+	     comms_mbx_msg_size - sizeof(uint32_t))) {
 		return RSE_COMMS_PROTOCOL_POINTER_ACCESS;
 	} else {
 		return RSE_COMMS_PROTOCOL_EMBED;
@@ -76,7 +75,7 @@
 	 * functions not being reentrant becomes a problem.
 	 */
 	static union rse_comms_io_buffer_t io_buf;
-	enum mhu_error_t err;
+	int err;
 	psa_status_t status;
 	static uint8_t seq_num = 1U;
 	size_t msg_size;
@@ -109,8 +108,8 @@
 		VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
 	}
 
-	err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
-	if (err != MHU_ERR_NONE) {
+	err = rse_mbx_send_data((uint8_t *)&io_buf.msg, msg_size);
+	if (err != 0) {
 		return PSA_ERROR_COMMUNICATION_FAILURE;
 	}
 
@@ -122,8 +121,8 @@
 	memset(&io_buf.msg, 0xA5, msg_size);
 #endif
 
-	err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
-	if (err != MHU_ERR_NONE) {
+	err = rse_mbx_receive_data((uint8_t *)&io_buf.reply, &reply_size);
+	if (err != 0) {
 		return PSA_ERROR_COMMUNICATION_FAILURE;
 	}
 
@@ -144,37 +143,10 @@
 		VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
 	}
 
-	/* Clear the MHU message buffer to remove assets from memory */
+	/* Clear the mailbox message buffer to remove assets from memory */
 	memset(&io_buf, 0x0, sizeof(io_buf));
 
 	seq_num++;
 
 	return return_val;
 }
-
-int rse_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
-{
-	enum mhu_error_t err;
-
-	err = mhu_init_sender(mhu_sender_base);
-	if (err != MHU_ERR_NONE) {
-		if (err == MHU_ERR_ALREADY_INIT) {
-			INFO("[RSE-COMMS] Host to RSE MHU driver already initialized\n");
-		} else {
-			ERROR("[RSE-COMMS] Host to RSE MHU driver initialization failed: %d\n", err);
-			return -1;
-		}
-	}
-
-	err = mhu_init_receiver(mhu_receiver_base);
-	if (err != MHU_ERR_NONE) {
-		if (err == MHU_ERR_ALREADY_INIT) {
-			INFO("[RSE-COMMS] RSE to Host MHU driver already initialized\n");
-		} else {
-			ERROR("[RSE-COMMS] RSE to Host MHU driver initialization failed: %d\n", err);
-			return -1;
-		}
-	}
-
-	return 0;
-}
diff --git a/drivers/arm/rse/rse_comms.mk b/drivers/arm/rse/rse_comms.mk
index 3b87fe2..743e978 100644
--- a/drivers/arm/rse/rse_comms.mk
+++ b/drivers/arm/rse/rse_comms.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -13,15 +13,16 @@
 					rse_comms_protocol_pointer_access.c	\
 				)
 
-# Default to MHUv2 if PLAT_MHU_VERSION undefined
-PLAT_MHU_VERSION ?= 2
+# Default to MHUv2 if PLAT_MHU undefined
+PLAT_MHU ?= MHUv2
 
-ifeq (${PLAT_MHU_VERSION}, 3)
+ifneq (${PLAT_MHU}, NO_MHU)
+ifeq (${PLAT_MHU}, MHUv3)
 RSE_COMMS_SOURCES	+=	$(addprefix drivers/arm/mhu/,			\
 					mhu_v3_x.c				\
 					mhu_wrapper_v3_x.c			\
 				)
-else ifeq (${PLAT_MHU_VERSION}, 2)
+else ifeq (${PLAT_MHU}, MHUv2)
 RSE_COMMS_SOURCES	+=	$(addprefix drivers/arm/mhu/,			\
 					mhu_v2_x.c				\
 					mhu_wrapper_v2_x.c			\
@@ -30,6 +31,12 @@
 $(error Unsupported MHU version)
 endif
 
+RSE_COMMS_SOURCES	+=	$(addprefix drivers/arm/rse/,			\
+					rse_comms_mhu.c				\
+				)
+
+PLAT_INCLUDES		+=	-Idrivers/arm/mhu
+endif
+
 PLAT_INCLUDES		+=	-Idrivers/arm/rse		\
-				-Idrivers/arm/mhu		\
 				-Iinclude/lib/psa
diff --git a/drivers/arm/rse/rse_comms_mhu.c b/drivers/arm/rse/rse_comms_mhu.c
new file mode 100644
index 0000000..8032393
--- /dev/null
+++ b/drivers/arm/rse/rse_comms_mhu.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/arm/mhu.h>
+#include <drivers/arm/rse_comms.h>
+
+size_t rse_mbx_get_max_message_size(void)
+{
+	return mhu_get_max_message_size();
+}
+
+int rse_mbx_send_data(const uint8_t *send_buffer, size_t size)
+{
+	enum mhu_error_t err = mhu_send_data(send_buffer, size);
+
+	if (err != MHU_ERR_NONE) {
+		ERROR("mhu_send_data err=%d\n", err);
+		return -1;
+	}
+
+	return 0;
+}
+
+int rse_mbx_receive_data(uint8_t *receive_buffer, size_t *size)
+{
+	enum mhu_error_t err = mhu_receive_data(receive_buffer, size);
+
+	if (err != MHU_ERR_NONE) {
+		ERROR("mhu_receive_data err=%d\n", err);
+		return -1;
+	}
+
+	return 0;
+}
+
+int rse_mbx_init(const void *init_data)
+{
+	enum mhu_error_t err;
+	const struct mhu_addr *mbx_addr = (const struct mhu_addr *)init_data;
+
+	err = mhu_init_sender(mbx_addr->sender_base);
+	if (err != MHU_ERR_NONE) {
+		if (err == MHU_ERR_ALREADY_INIT) {
+			INFO("[RSE-COMMS] Host to RSE MHU driver already initialized\n");
+		} else {
+			ERROR("[RSE-COMMS] Host to RSE MHU driver initialization failed: %d\n",
+			      err);
+			return -1;
+		}
+	}
+
+	err = mhu_init_receiver(mbx_addr->receiver_base);
+	if (err != MHU_ERR_NONE) {
+		if (err == MHU_ERR_ALREADY_INIT) {
+			INFO("[RSE-COMMS] RSE to Host MHU driver already initialized\n");
+		} else {
+			ERROR("[RSE-COMMS] RSE to Host MHU driver initialization failed: %d\n",
+			      err);
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
index 665930b..79e5ed1 100644
--- a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
+++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
@@ -11,6 +11,7 @@
 #define ARMPLL_BASE_ADDR		(0x40038000UL)
 #define PERIPHPLL_BASE_ADDR		(0x4003C000UL)
 #define ARM_DFS_BASE_ADDR		(0x40054000UL)
+#define PERIPH_DFS_BASE_ADDR		(0x40058000UL)
 #define CGM0_BASE_ADDR			(0x40030000UL)
 #define CGM1_BASE_ADDR			(0x40034000UL)
 #define DDRPLL_BASE_ADDR		(0x40044000UL)
@@ -92,6 +93,25 @@
 #define MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE	0x5U
 #define MC_CGM_MUXn_CSS_SWIP		BIT_32(16U)
 #define MC_CGM_MUXn_CSS_SAFE_SW		BIT_32(3U)
+#define MC_CGM_MUXn_DCm(CGM_ADDR, MUX, DC) \
+					(((CGM_ADDR) + 0x308UL) + \
+					 ((MUX) * 0x40UL) + ((DC) * 0x4UL))
+#define MC_CGM_MUXn_DCm_DIV_OFFSET	(16U)
+#define MC_CGM_MUXn_DCm_DIV_MASK	GENMASK_32(23U, MC_CGM_MUXn_DCm_DIV_OFFSET)
+#define MC_CGM_MUXn_DCm_DIV_SET(VAL)	(MC_CGM_MUXn_DCm_DIV_MASK & ((VAL) \
+					 << MC_CGM_MUXn_DCm_DIV_OFFSET))
+#define MC_CGM_MUXn_DCm_DIV(VAL)	((MC_CGM_MUXn_DCm_DIV_MASK & (VAL)) \
+					 >> MC_CGM_MUXn_DCm_DIV_OFFSET)
+#define MC_CGM_MUXn_DCm_DE		BIT_32(31U)
+#define MC_CGM_MUXn_DIV_UPD_STAT(CGM_ADDR, MUX) \
+					(((CGM_ADDR) + 0x33CUL + ((MUX) * 0x40UL)))
+#define MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT_OFFSET	(0U)
+#define MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT(CSS) \
+					((MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT_MASK \
+					  & (CSS)) \
+					  >> MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT_OFFSET)
+#define MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT_MASK	BIT_32(0U)
+
 
 /* DFS */
 #define DFS_PORTSR(DFS_ADDR)		((DFS_ADDR) + 0xCUL)
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index c235e04..0a71152 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -24,6 +24,7 @@
 	uintptr_t armpll_base;
 	uintptr_t periphpll_base;
 	uintptr_t armdfs_base;
+	uintptr_t periphdfs_base;
 	uintptr_t cgm0_base;
 	uintptr_t cgm1_base;
 	uintptr_t cgm5_base;
@@ -58,6 +59,7 @@
 		.armpll_base = ARMPLL_BASE_ADDR,
 		.periphpll_base = PERIPHPLL_BASE_ADDR,
 		.armdfs_base = ARM_DFS_BASE_ADDR,
+		.periphdfs_base = PERIPH_DFS_BASE_ADDR,
 		.cgm0_base = CGM0_BASE_ADDR,
 		.cgm1_base = CGM1_BASE_ADDR,
 		.cgm5_base = MC_CGM5_BASE_ADDR,
@@ -110,6 +112,9 @@
 	case S32CC_ARM_DFS:
 		*base = drv->armdfs_base;
 		break;
+	case S32CC_PERIPH_DFS:
+		*base = drv->periphdfs_base;
+		break;
 	case S32CC_CGM0:
 		*base = drv->cgm0_base;
 		break;
@@ -1085,6 +1090,232 @@
 	return get_module_rate(block->parent, drv, rate, ldepth);
 }
 
+static void cgm_mux_div_config(uintptr_t cgm_addr, uint32_t mux,
+			       uint32_t dc, uint32_t div_index)
+{
+	uint32_t updstat;
+	uint32_t dc_val = mmio_read_32(MC_CGM_MUXn_DCm(cgm_addr, mux, div_index));
+
+	dc_val &= (MC_CGM_MUXn_DCm_DIV_MASK | MC_CGM_MUXn_DCm_DE);
+
+	if (dc_val == (MC_CGM_MUXn_DCm_DE | MC_CGM_MUXn_DCm_DIV_SET(dc))) {
+		return;
+	}
+
+	/* Set the divider */
+	mmio_write_32(MC_CGM_MUXn_DCm(cgm_addr, mux, div_index),
+		      MC_CGM_MUXn_DCm_DE | MC_CGM_MUXn_DCm_DIV_SET(dc));
+
+	/* Wait for divider to get updated */
+	do {
+		updstat = mmio_read_32(MC_CGM_MUXn_DIV_UPD_STAT(cgm_addr, mux));
+	} while (MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT(updstat) != 0U);
+}
+
+static inline struct s32cc_clkmux *get_cgm_div_mux(const struct s32cc_cgm_div *cgm_div)
+{
+	const struct s32cc_clk_obj *parent = cgm_div->parent;
+	const struct s32cc_clk_obj *mux_obj;
+	const struct s32cc_clk *clk;
+
+	if (parent == NULL) {
+		ERROR("Failed to identify CGM DIV's parent\n");
+		return NULL;
+	}
+
+	if (parent->type != s32cc_clk_t) {
+		ERROR("The parent of the CGM DIV isn't a clock\n");
+		return NULL;
+	}
+
+	clk = s32cc_obj2clk(parent);
+
+	if (clk->module == NULL) {
+		ERROR("The clock isn't connected to a module\n");
+		return NULL;
+	}
+
+	mux_obj = clk->module;
+
+	if ((mux_obj->type != s32cc_clkmux_t) &&
+	    (mux_obj->type != s32cc_shared_clkmux_t)) {
+		ERROR("The parent of the CGM DIV isn't a MUX\n");
+		return NULL;
+	}
+
+	return s32cc_obj2clkmux(mux_obj);
+}
+
+static int enable_cgm_div(struct s32cc_clk_obj *module,
+			  const struct s32cc_clk_drv *drv, unsigned int depth)
+{
+	const struct s32cc_cgm_div *cgm_div = s32cc_obj2cgmdiv(module);
+	const struct s32cc_clkmux *mux;
+	unsigned int ldepth = depth;
+	uintptr_t cgm_addr = 0ULL;
+	uint64_t pfreq, dc64;
+	uint32_t dc;
+	int ret;
+
+	ret = update_stack_depth(&ldepth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (cgm_div->parent == NULL) {
+		ERROR("Failed to identify CGM divider's parent\n");
+		return -EINVAL;
+	}
+
+	if (cgm_div->freq == 0U) {
+		ERROR("The frequency of the divider %" PRIu32 " is not set\n",
+		      cgm_div->index);
+		return -EINVAL;
+	}
+
+	mux = get_cgm_div_mux(cgm_div);
+	if (mux == NULL) {
+		return -EINVAL;
+	}
+
+	ret = get_base_addr(mux->module, drv, &cgm_addr);
+	if (ret != 0) {
+		ERROR("Failed to get CGM base address of the MUX module %d\n",
+		      mux->module);
+		return ret;
+	}
+
+	ret = get_module_rate(cgm_div->parent, drv, &pfreq, ldepth);
+	if (ret != 0) {
+		ERROR("Failed to enable the div due to unknown frequency of "
+		      "the CGM MUX %" PRIu8 "(CGM=%" PRIxPTR ")\n",
+		      mux->index, cgm_addr);
+		return -EINVAL;
+	}
+
+	dc64 = ((pfreq * FP_PRECISION) / cgm_div->freq) / FP_PRECISION;
+	dc = (uint32_t)dc64;
+
+	if ((pfreq / dc64) != cgm_div->freq) {
+		ERROR("Cannot set CGM divider (mux:%" PRIu8 ", div:%" PRIu32
+		      ") for input = %lu & output = %lu, Nearest freq = %lu\n",
+		mux->index, cgm_div->index, (unsigned long)pfreq,
+		cgm_div->freq, (unsigned long)(pfreq / dc));
+		return -EINVAL;
+	}
+
+	cgm_mux_div_config(cgm_addr, mux->index, dc - 1U, cgm_div->index);
+	return 0;
+}
+
+static int set_cgm_div_freq(const struct s32cc_clk_obj *module,
+			    unsigned long rate, unsigned long *orate,
+			    unsigned int *depth)
+{
+	struct s32cc_cgm_div *cgm_div = s32cc_obj2cgmdiv(module);
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (cgm_div->parent == NULL) {
+		ERROR("Failed to identify the CGM divider's parent\n");
+		return -EINVAL;
+	}
+
+	cgm_div->freq = rate;
+	*orate = rate;
+
+	return 0;
+}
+
+static inline bool is_cgm_div_enabled(uintptr_t cgm_addr, uint32_t mux,
+				      uint32_t div_index)
+{
+	uint32_t dc_val;
+
+	dc_val = mmio_read_32(MC_CGM_MUXn_DCm(cgm_addr, mux, div_index));
+
+	return ((dc_val & MC_CGM_MUXn_DCm_DE) != 0U);
+}
+
+static unsigned long calc_cgm_div_freq(uintptr_t cgm_addr, uint32_t mux,
+				       uint32_t div_index, unsigned long pfreq)
+{
+	uint32_t dc_val;
+	uint32_t dc_div;
+
+	dc_val = mmio_read_32(MC_CGM_MUXn_DCm(cgm_addr, mux, div_index));
+	dc_div = MC_CGM_MUXn_DCm_DIV(dc_val) + 1U;
+
+	return pfreq * FP_PRECISION / dc_div / FP_PRECISION;
+}
+
+static int get_cgm_div_freq(const struct s32cc_clk_obj *module,
+			    const struct s32cc_clk_drv *drv,
+			    unsigned long *rate, unsigned int depth)
+{
+	const struct s32cc_cgm_div *cgm_div = s32cc_obj2cgmdiv(module);
+	const struct s32cc_clkmux *mux;
+	unsigned int ldepth = depth;
+	uintptr_t cgm_addr = 0ULL;
+	unsigned long pfreq;
+	int ret;
+
+	ret = update_stack_depth(&ldepth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (cgm_div->parent == NULL) {
+		ERROR("Failed to identify CGM divider's parent\n");
+		return -EINVAL;
+	}
+
+	mux = get_cgm_div_mux(cgm_div);
+	if (mux == NULL) {
+		return -EINVAL;
+	}
+
+	ret = get_base_addr(mux->module, drv, &cgm_addr);
+	if (ret != 0) {
+		ERROR("Failed to get CGM base address of the MUX module %d\n",
+		      mux->module);
+		return ret;
+	}
+
+	if (!is_cgm_div_enabled(cgm_addr, mux->index, cgm_div->index)) {
+		*rate = cgm_div->freq;
+		return 0;
+	}
+
+	ret = get_module_rate(cgm_div->parent, drv, &pfreq, ldepth);
+	if (ret != 0) {
+		ERROR("Failed to get the frequency of CGM MUX %" PRIu8 "(CGM=0x%" PRIxPTR ")\n",
+		      mux->index, cgm_addr);
+		return ret;
+	}
+
+	*rate = calc_cgm_div_freq(cgm_addr, mux->index, cgm_div->index, pfreq);
+
+	return 0;
+}
+
+static struct s32cc_clk_obj *
+get_cgm_div_parent(const struct s32cc_clk_obj *module)
+{
+	const struct s32cc_cgm_div *cgm_div = s32cc_obj2cgmdiv(module);
+
+	if (cgm_div->parent == NULL) {
+		ERROR("Failed to identify the CGM divider's parent\n");
+		return NULL;
+	}
+
+	return cgm_div->parent;
+}
+
 static int no_enable(struct s32cc_clk_obj *module,
 		     const struct s32cc_clk_drv *drv,
 		     unsigned int depth)
@@ -1131,7 +1362,7 @@
 			 unsigned int depth)
 {
 	struct s32cc_clk_obj *parent = get_module_parent(module);
-	static const enable_clk_t enable_clbs[12] = {
+	static const enable_clk_t enable_clbs[13] = {
 		[s32cc_clk_t] = no_enable,
 		[s32cc_osc_t] = enable_osc,
 		[s32cc_pll_t] = enable_pll,
@@ -1143,6 +1374,7 @@
 		[s32cc_part_t] = enable_part,
 		[s32cc_part_block_t] = enable_part_block,
 		[s32cc_part_block_link_t] = enable_part_block_link,
+		[s32cc_cgm_div_t] = enable_cgm_div,
 	};
 	unsigned int ldepth = depth;
 	uint32_t index;
@@ -1558,6 +1790,13 @@
 	return 0;
 }
 
+static inline struct s32cc_clk_obj *get_fixed_div_parent(const struct s32cc_clk_obj *module)
+{
+	const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module);
+
+	return fdiv->parent;
+}
+
 static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate,
 			unsigned long *orate, unsigned int *depth)
 {
@@ -1703,6 +1942,28 @@
 	return 0;
 }
 
+static int set_part_block_link_freq(const struct s32cc_clk_obj *module,
+				    unsigned long rate, unsigned long *orate,
+				    const unsigned int *depth)
+{
+	const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module);
+	const struct s32cc_clk_obj *parent = link->parent;
+	unsigned int ldepth = *depth;
+	int ret;
+
+	ret = update_stack_depth(&ldepth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (parent == NULL) {
+		ERROR("Partition block link with no parent\n");
+		return -EINVAL;
+	}
+
+	return set_module_rate(parent, rate, orate, &ldepth);
+}
+
 static int set_module_rate(const struct s32cc_clk_obj *module,
 			   unsigned long rate, unsigned long *orate,
 			   unsigned int *depth)
@@ -1738,12 +1999,24 @@
 	case s32cc_shared_clkmux_t:
 		ret = set_mux_freq(module, rate, orate, depth);
 		break;
+	case s32cc_cgm_div_t:
+		ret = set_cgm_div_freq(module, rate, orate, depth);
+		break;
 	case s32cc_dfs_t:
 		ERROR("Setting the frequency of a DFS is not allowed!");
 		break;
 	case s32cc_dfs_div_t:
 		ret = set_dfs_div_freq(module, rate, orate, depth);
 		break;
+	case s32cc_part_block_link_t:
+		ret = set_part_block_link_freq(module, rate, orate, depth);
+		break;
+	case s32cc_part_t:
+		ERROR("It's not allowed to set the frequency of a partition !");
+		break;
+	case s32cc_part_block_t:
+		ERROR("It's not allowed to set the frequency of a partition block !");
+		break;
 	default:
 		break;
 	}
@@ -1801,6 +2074,9 @@
 	case s32cc_part_block_link_t:
 		ret = get_part_block_link_freq(module, drv, rate, ldepth);
 		break;
+	case s32cc_cgm_div_t:
+		ret = get_cgm_div_freq(module, drv, rate, ldepth);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -1862,7 +2138,7 @@
 
 static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module)
 {
-	static const get_parent_clb_t parents_clbs[12] = {
+	static const get_parent_clb_t parents_clbs[13] = {
 		[s32cc_clk_t] = get_clk_parent,
 		[s32cc_osc_t] = get_no_parent,
 		[s32cc_pll_t] = get_pll_parent,
@@ -1872,8 +2148,10 @@
 		[s32cc_dfs_t] = get_dfs_parent,
 		[s32cc_dfs_div_t] = get_dfs_div_parent,
 		[s32cc_part_t] = get_no_parent,
+		[s32cc_fixed_div_t] = get_fixed_div_parent,
 		[s32cc_part_block_t] = get_part_block_parent,
 		[s32cc_part_block_link_t] = get_part_block_link_parent,
+		[s32cc_cgm_div_t] = get_cgm_div_parent,
 	};
 	uint32_t index;
 
@@ -1980,11 +2258,12 @@
 
 static int s32cc_clk_mmap_regs(const struct s32cc_clk_drv *drv)
 {
-	const uintptr_t base_addrs[11] = {
+	const uintptr_t base_addrs[12] = {
 		drv->fxosc_base,
 		drv->armpll_base,
 		drv->periphpll_base,
 		drv->armdfs_base,
+		drv->periphdfs_base,
 		drv->cgm0_base,
 		drv->cgm1_base,
 		drv->cgm5_base,
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
index f7af465..127453e 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
@@ -68,6 +68,12 @@
 				 S32CC_CLK_FXOSC, 0, 0);
 static struct s32cc_clk cgm0_mux8_clk = S32CC_MODULE_CLK(cgm0_mux8);
 
+static struct s32cc_clkmux cgm0_mux14 =
+	S32CC_CLKMUX_INIT(S32CC_CGM0, 14, 2,
+			  S32CC_CLK_FIRC,
+			  S32CC_CLK_PERIPH_PLL_DFS3, 0, 0, 0);
+static struct s32cc_clk cgm0_mux14_clk = S32CC_MODULE_CLK(cgm0_mux14);
+
 /* XBAR */
 static struct s32cc_clk xbar_2x_clk =
 	S32CC_CHILD_CLK(cgm0_mux0_clk, 48 * MHZ, 800 * MHZ);
@@ -142,6 +148,14 @@
 static struct s32cc_clk periph_pll_phi3_clk =
 	S32CC_FREQ_MODULE_CLK(periph_pll_phi3_div, 0, 133333333);
 
+/* PERIPH DFS */
+static struct s32cc_dfs periphdfs =
+	S32CC_DFS_INIT(periphpll, S32CC_PERIPH_DFS);
+static struct s32cc_dfs_div periph_dfs3_div =
+	S32CC_DFS_DIV_INIT(periphdfs, 0);
+static struct s32cc_clk periph_dfs3_clk =
+	S32CC_FREQ_MODULE_CLK(periph_dfs3_div, 416 * MHZ, 800 * MHZ);
+
 /* DDR PLL */
 static struct s32cc_clkmux ddr_pll_mux =
 	S32CC_CLKMUX_INIT(S32CC_DDR_PLL, 0, 2,
@@ -175,6 +189,15 @@
 static struct s32cc_clk ddr_clk =
 	S32CC_FREQ_MODULE_CLK(ddr_block_link, 0, 800 * MHZ);
 
+/* SDHC_CLK */
+static struct s32cc_part_block part0_block0 =
+	S32CC_PART_BLOCK(&part0, s32cc_part_block0);
+static struct s32cc_cgm_div sdhc_div = S32CC_CGM_DIV_INIT(cgm0_mux14_clk, 0);
+static struct s32cc_part_block_link usdhc_block_link =
+	S32CC_PART_BLOCK_LINK(sdhc_div, &part0_block0);
+static struct s32cc_clk usdhc_clk =
+	S32CC_FREQ_MODULE_CLK(usdhc_block_link, 0, 400 * MHZ);
+
 static struct s32cc_clk *s32cc_hw_clk_list[37] = {
 	/* Oscillators */
 	[S32CC_CLK_ID(S32CC_CLK_FIRC)] = &firc_clk,
@@ -186,6 +209,8 @@
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_DFS1)] = &arm_dfs1_clk,
 	/* PERIPH PLL */
 	[S32CC_CLK_ID(S32CC_CLK_PERIPH_PLL_PHI3)] = &periph_pll_phi3_clk,
+	/* PERIPH DFS */
+	[S32CC_CLK_ID(S32CC_CLK_PERIPH_PLL_DFS3)] = &periph_dfs3_clk,
 	/* DDR PLL */
 	[S32CC_CLK_ID(S32CC_CLK_DDR_PLL_PHI0)] = &ddr_pll_phi0_clk,
 };
@@ -196,7 +221,7 @@
 	.n_clks = ARRAY_SIZE(s32cc_hw_clk_list),
 };
 
-static struct s32cc_clk *s32cc_arch_clk_list[22] = {
+static struct s32cc_clk *s32cc_arch_clk_list[24] = {
 	/* ARM PLL */
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_MUX)] = &arm_pll_mux_clk,
 	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_VCO)] = &arm_pll_vco_clk,
@@ -206,6 +231,7 @@
 	/* MC_CGM0 */
 	[S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX0)] = &cgm0_mux0_clk,
 	[S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX8)] = &cgm0_mux8_clk,
+	[S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX14)] = &cgm0_mux14_clk,
 	/* XBAR */
 	[S32CC_CLK_ID(S32CC_CLK_XBAR_2X)] = &xbar_2x_clk,
 	[S32CC_CLK_ID(S32CC_CLK_XBAR)] = &xbar_clk,
@@ -229,6 +255,8 @@
 	[S32CC_CLK_ID(S32CC_CLK_MC_CGM5_MUX0)] = &cgm5_mux0_clk,
 	/* DDR */
 	[S32CC_CLK_ID(S32CC_CLK_DDR)] = &ddr_clk,
+	/* USDHC */
+	[S32CC_CLK_ID(S32CC_CLK_USDHC)] = &usdhc_clk,
 };
 
 static struct s32cc_clk_array s32cc_arch_clocks = {
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index f001568..92182a0 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 NXP
+ * Copyright 2024-2025 NXP
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,6 +18,8 @@
 #define S32CC_PERIPH_PLL_PHI3_FREQ	UART_CLOCK_HZ
 #define S32CC_DDR_PLL_VCO_FREQ		(1600U * MHZ)
 #define S32CC_DDR_PLL_PHI0_FREQ		(800U * MHZ)
+#define S32CC_PERIPH_DFS_PHI3_FREQ	(800U * MHZ)
+#define S32CC_USDHC_FREQ		(400U * MHZ)
 
 static int setup_fxosc(void)
 {
@@ -180,6 +182,35 @@
 	return ret;
 }
 
+static int enable_usdhc_clk(void)
+{
+	int ret;
+
+	ret = clk_set_parent(S32CC_CLK_MC_CGM0_MUX14,
+			     S32CC_CLK_PERIPH_PLL_DFS3);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_set_rate(S32CC_CLK_PERIPH_PLL_DFS3,
+			   S32CC_PERIPH_DFS_PHI3_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_set_rate(S32CC_CLK_USDHC, S32CC_USDHC_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_enable(S32CC_CLK_USDHC);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return ret;
+}
+
 int s32cc_init_core_clocks(void)
 {
 	int ret;
@@ -241,5 +272,10 @@
 		return ret;
 	}
 
+	ret = enable_usdhc_clk();
+	if (ret != 0) {
+		return ret;
+	}
+
 	return ret;
 }
diff --git a/drivers/st/pmic/stpmic2.c b/drivers/st/pmic/stpmic2.c
index 05a80ec..7f233db 100644
--- a/drivers/st/pmic/stpmic2.c
+++ b/drivers/st/pmic/stpmic2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2024-2025, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -247,10 +247,6 @@
 {
 	const struct regul_struct *regul = &regul_table[id];
 
-	if (regul == NULL) {
-		return RET_ERROR_BAD_PARAMETERS;
-	}
-
 	if (levels_count != NULL) {
 		*levels_count = regul->volt_table_size;
 	}
diff --git a/fdts/fvp-base-psci-common.dtsi b/fdts/fvp-base-psci-common.dtsi
index 583bba7..95ea2a1 100644
--- a/fdts/fvp-base-psci-common.dtsi
+++ b/fdts/fvp-base-psci-common.dtsi
@@ -7,7 +7,7 @@
  *
  * RTSM_VE_AEMv8A.lisa
  *
- * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, ARM Limited and Contributors. All rights reserved.
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -249,4 +249,39 @@
 				<0 0 44 &gic 0 GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
 				<0 0 46 &gic 0 GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 	};
+
+#if (ENABLE_RME == 1)
+	pci: pci@40000000 {
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		compatible = "pci-host-ecam-generic";
+		device_type = "pci";
+		reg = <0x0 0x40000000 0x0 0x10000000>;
+		ranges = <0x2000000 0x0 0x50000000 0x0 0x50000000 0x0 0x10000000>,
+			/* First 3GB of 256GB PCIe memory region 2 */
+			 <0x2000000 0x40 0x00000000 0x40 0x00000000 0x0 0xc0000000>;
+		interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 2 &gic 0 0 GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 3 &gic 0 0 GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>,
+				<0 0 0 4 &gic 0 0 GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+		msi-map = <0x0 &its 0x0 0x10000>;
+		iommu-map = <0x0 &smmu 0x0 0x10000>;
+		dma-coherent;
+	};
+
+	smmu: iommu@2b400000 {
+		compatible = "arm,smmu-v3";
+		reg = <0x0 0x2b400000 0x0 0x100000>;
+		interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
+			     <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>,
+			     <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
+			     <GIC_SPI 77 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "eventq", "gerror", "priq", "cmdq-sync";
+		dma-coherent;
+		#iommu-cells = <1>;
+		msi-parent = <&its 0x10000>;
+	};
+#endif /* ENABLE_RME */
 };
diff --git a/fdts/stm32mp157a-dk1-sp_min-fw-config.dts b/fdts/stm32mp157a-dk1-sp_min-fw-config.dts
new file mode 100644
index 0000000..40164f3
--- /dev/null
+++ b/fdts/stm32mp157a-dk1-sp_min-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE	0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157a-dk1-sp_min.dts b/fdts/stm32mp157a-dk1-sp_min.dts
new file mode 100644
index 0000000..ac5c2af
--- /dev/null
+++ b/fdts/stm32mp157a-dk1-sp_min.dts
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#include "stm32mp157a-dk1.dts"
+
+/ {
+	model = "STMicroelectronics STM32MP157A-DK1 Discovery Board (SP_MIN)";
+};
+
+&rcc {
+	st,clksrc = <
+		CLK_MPU_PLL1P
+		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
+		CLK_RTC_LSE
+		CLK_MCO1_DISABLED
+		CLK_MCO2_DISABLED
+		CLK_CKPER_HSE
+		CLK_FMC_ACLK
+		CLK_QSPI_ACLK
+		CLK_ETH_PLL4P
+		CLK_SDMMC12_PLL4P
+		CLK_DSI_DSIPLL
+		CLK_STGEN_HSE
+		CLK_USBPHY_HSE
+		CLK_SPI2S1_PLL3Q
+		CLK_SPI2S23_PLL3Q
+		CLK_SPI45_HSI
+		CLK_SPI6_HSI
+		CLK_I2C46_HSI
+		CLK_SDMMC3_PLL4P
+		CLK_USBO_USBPHY
+		CLK_ADC_CKPER
+		CLK_CEC_LSE
+		CLK_I2C12_HSI
+		CLK_I2C35_HSI
+		CLK_UART1_HSI
+		CLK_UART24_HSI
+		CLK_UART35_HSI
+		CLK_UART6_HSI
+		CLK_UART78_HSI
+		CLK_SPDIF_PLL4P
+		CLK_FDCAN_PLL4R
+		CLK_SAI1_PLL3Q
+		CLK_SAI2_PLL3Q
+		CLK_SAI3_PLL3Q
+		CLK_SAI4_PLL3Q
+		CLK_RNG1_CSI
+		CLK_RNG2_LSI
+		CLK_LPTIM1_PCLK1
+		CLK_LPTIM23_PCLK3
+		CLK_LPTIM45_LSE
+	>;
+
+	st,clkdiv = <
+		DIV(DIV_MPU, 1)
+		DIV(DIV_AXI, 0)
+		DIV(DIV_MCU, 0)
+		DIV(DIV_APB1, 1)
+		DIV(DIV_APB2, 1)
+		DIV(DIV_APB3, 1)
+		DIV(DIV_APB4, 1)
+		DIV(DIV_APB5, 2)
+		DIV(DIV_MCO1, 0)
+		DIV(DIV_MCO2, 0)
+	>;
+};
diff --git a/fdts/stm32mp157c-dk2-sp_min-fw-config.dts b/fdts/stm32mp157c-dk2-sp_min-fw-config.dts
new file mode 100644
index 0000000..40164f3
--- /dev/null
+++ b/fdts/stm32mp157c-dk2-sp_min-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE	0x20000000 /* 512MB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-dk2-sp_min.dts b/fdts/stm32mp157c-dk2-sp_min.dts
new file mode 100644
index 0000000..350cd34
--- /dev/null
+++ b/fdts/stm32mp157c-dk2-sp_min.dts
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#include "stm32mp157c-dk2.dts"
+
+/ {
+	model = "STMicroelectronics STM32MP157C-DK2 Discovery Board (SP_MIN)";
+};
+
+&rcc {
+	st,clksrc = <
+		CLK_MPU_PLL1P
+		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
+		CLK_RTC_LSE
+		CLK_MCO1_DISABLED
+		CLK_MCO2_DISABLED
+		CLK_CKPER_HSE
+		CLK_FMC_ACLK
+		CLK_QSPI_ACLK
+		CLK_ETH_PLL4P
+		CLK_SDMMC12_PLL4P
+		CLK_DSI_DSIPLL
+		CLK_STGEN_HSE
+		CLK_USBPHY_HSE
+		CLK_SPI2S1_PLL3Q
+		CLK_SPI2S23_PLL3Q
+		CLK_SPI45_HSI
+		CLK_SPI6_HSI
+		CLK_I2C46_HSI
+		CLK_SDMMC3_PLL4P
+		CLK_USBO_USBPHY
+		CLK_ADC_CKPER
+		CLK_CEC_LSE
+		CLK_I2C12_HSI
+		CLK_I2C35_HSI
+		CLK_UART1_HSI
+		CLK_UART24_HSI
+		CLK_UART35_HSI
+		CLK_UART6_HSI
+		CLK_UART78_HSI
+		CLK_SPDIF_PLL4P
+		CLK_FDCAN_PLL4R
+		CLK_SAI1_PLL3Q
+		CLK_SAI2_PLL3Q
+		CLK_SAI3_PLL3Q
+		CLK_SAI4_PLL3Q
+		CLK_RNG1_CSI
+		CLK_RNG2_LSI
+		CLK_LPTIM1_PCLK1
+		CLK_LPTIM23_PCLK3
+		CLK_LPTIM45_LSE
+	>;
+
+	st,clkdiv = <
+		DIV(DIV_MPU, 1)
+		DIV(DIV_AXI, 0)
+		DIV(DIV_MCU, 0)
+		DIV(DIV_APB1, 1)
+		DIV(DIV_APB2, 1)
+		DIV(DIV_APB3, 1)
+		DIV(DIV_APB4, 1)
+		DIV(DIV_APB5, 2)
+		DIV(DIV_MCO1, 0)
+		DIV(DIV_MCO2, 0)
+	>;
+};
diff --git a/fdts/stm32mp157c-ed1-sp_min-fw-config.dts b/fdts/stm32mp157c-ed1-sp_min-fw-config.dts
new file mode 100644
index 0000000..5aff97f
--- /dev/null
+++ b/fdts/stm32mp157c-ed1-sp_min-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE	0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-ed1-sp_min.dts b/fdts/stm32mp157c-ed1-sp_min.dts
new file mode 100644
index 0000000..85d4fb1
--- /dev/null
+++ b/fdts/stm32mp157c-ed1-sp_min.dts
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#include "stm32mp157c-ed1.dts"
+
+/ {
+	model = "STMicroelectronics STM32MP157C eval daughter (SP_MIN)";
+};
+
+&rcc {
+	st,clksrc = <
+		CLK_MPU_PLL1P
+		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
+		CLK_RTC_LSE
+		CLK_MCO1_DISABLED
+		CLK_MCO2_DISABLED
+		CLK_CKPER_HSE
+		CLK_FMC_ACLK
+		CLK_QSPI_ACLK
+		CLK_ETH_PLL4P
+		CLK_SDMMC12_PLL4P
+		CLK_DSI_DSIPLL
+		CLK_STGEN_HSE
+		CLK_USBPHY_HSE
+		CLK_SPI2S1_PLL3Q
+		CLK_SPI2S23_PLL3Q
+		CLK_SPI45_HSI
+		CLK_SPI6_HSI
+		CLK_I2C46_HSI
+		CLK_SDMMC3_PLL4P
+		CLK_USBO_USBPHY
+		CLK_ADC_CKPER
+		CLK_CEC_LSE
+		CLK_I2C12_HSI
+		CLK_I2C35_HSI
+		CLK_UART1_HSI
+		CLK_UART24_HSI
+		CLK_UART35_HSI
+		CLK_UART6_HSI
+		CLK_UART78_HSI
+		CLK_SPDIF_PLL4P
+		CLK_FDCAN_PLL4R
+		CLK_SAI1_PLL3Q
+		CLK_SAI2_PLL3Q
+		CLK_SAI3_PLL3Q
+		CLK_SAI4_PLL3Q
+		CLK_RNG1_CSI
+		CLK_RNG2_LSI
+		CLK_LPTIM1_PCLK1
+		CLK_LPTIM23_PCLK3
+		CLK_LPTIM45_LSE
+	>;
+
+	st,clkdiv = <
+		DIV(DIV_MPU, 1)
+		DIV(DIV_AXI, 0)
+		DIV(DIV_MCU, 0)
+		DIV(DIV_APB1, 1)
+		DIV(DIV_APB2, 1)
+		DIV(DIV_APB3, 1)
+		DIV(DIV_APB4, 1)
+		DIV(DIV_APB5, 2)
+		DIV(DIV_MCO1, 0)
+		DIV(DIV_MCO2, 0)
+	>;
+};
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
index fe5f464..dddfe3a 100644
--- a/fdts/stm32mp157c-ed1.dts
+++ b/fdts/stm32mp157c-ed1.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
- * Copyright (c) 2017-2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2025, STMicroelectronics - All Rights Reserved
  * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
  */
 /dts-v1/;
@@ -195,43 +195,13 @@
 		CLK_AXI_PLL2P
 		CLK_MCU_PLL3P
 		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
 		CLK_CKPER_HSE
 		CLK_FMC_ACLK
 		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
 		CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL
 		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_PLL3Q
-		CLK_SPI2S23_PLL3Q
-		CLK_SPI45_HSI
-		CLK_SPI6_HSI
 		CLK_I2C46_HSI
-		CLK_SDMMC3_PLL4P
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_LSE
-		CLK_I2C12_HSI
-		CLK_I2C35_HSI
-		CLK_UART1_HSI
 		CLK_UART24_HSI
-		CLK_UART35_HSI
-		CLK_UART6_HSI
-		CLK_UART78_HSI
-		CLK_SPDIF_PLL4P
-		CLK_FDCAN_PLL4R
-		CLK_SAI1_PLL3Q
-		CLK_SAI2_PLL3Q
-		CLK_SAI3_PLL3Q
-		CLK_SAI4_PLL3Q
-		CLK_RNG1_CSI
-		CLK_RNG2_LSI
-		CLK_LPTIM1_PCLK1
-		CLK_LPTIM23_PCLK3
-		CLK_LPTIM45_LSE
 	>;
 
 	st,clkdiv = <
@@ -244,8 +214,6 @@
 		DIV(DIV_APB4, 1)
 		DIV(DIV_APB5, 2)
 		DIV(DIV_RTC, 23)
-		DIV(DIV_MCO1, 0)
-		DIV(DIV_MCO2, 0)
 	>;
 
 	st,pll_vco {
diff --git a/fdts/stm32mp157c-ev1-sp_min-fw-config.dts b/fdts/stm32mp157c-ev1-sp_min-fw-config.dts
new file mode 100644
index 0000000..5aff97f
--- /dev/null
+++ b/fdts/stm32mp157c-ev1-sp_min-fw-config.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#define DDR_SIZE	0x40000000 /* 1GB */
+#include "stm32mp15-fw-config.dtsi"
diff --git a/fdts/stm32mp157c-ev1-sp_min.dts b/fdts/stm32mp157c-ev1-sp_min.dts
new file mode 100644
index 0000000..9513449
--- /dev/null
+++ b/fdts/stm32mp157c-ev1-sp_min.dts
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (c) 2017-2025, STMicroelectronics - All Rights Reserved
+ */
+/dts-v1/;
+
+#include "stm32mp157c-ed1-sp_min.dts"
+
+/ {
+	model = "STMicroelectronics STM32MP157C eval daughter on eval mother (SP_MIN)";
+	compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157";
+
+	aliases {
+		serial1 = &usart3;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&fmc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&fmc_pins_a>;
+	status = "okay";
+
+	nand-controller@4,0 {
+		status = "okay";
+
+		nand@0 {
+			reg = <0>;
+			nand-on-flash-bbt;
+			#address-cells = <1>;
+			#size-cells = <1>;
+		};
+	};
+};
+
+&qspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&qspi_clk_pins_a
+		     &qspi_bk1_pins_a
+		     &qspi_cs1_pins_a>;
+	reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	flash0: flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-rx-bus-width = <4>;
+		spi-max-frequency = <108000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&usart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usart3_pins_b>;
+	uart-has-rtscts;
+	status = "disabled";
+};
diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi
index 3115a00..1c7c4c3 100644
--- a/fdts/stm32mp15xx-dkx.dtsi
+++ b/fdts/stm32mp15xx-dkx.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
 /*
- * Copyright (c) 2019-2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2025, STMicroelectronics - All Rights Reserved
  * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  */
 
@@ -199,43 +199,11 @@
 		CLK_AXI_PLL2P
 		CLK_MCU_PLL3P
 		CLK_RTC_LSE
-		CLK_MCO1_DISABLED
-		CLK_MCO2_DISABLED
 		CLK_CKPER_HSE
-		CLK_FMC_ACLK
-		CLK_QSPI_ACLK
-		CLK_ETH_PLL4P
 		CLK_SDMMC12_PLL4P
-		CLK_DSI_DSIPLL
 		CLK_STGEN_HSE
-		CLK_USBPHY_HSE
-		CLK_SPI2S1_PLL3Q
-		CLK_SPI2S23_PLL3Q
-		CLK_SPI45_HSI
-		CLK_SPI6_HSI
 		CLK_I2C46_HSI
-		CLK_SDMMC3_PLL4P
-		CLK_USBO_USBPHY
-		CLK_ADC_CKPER
-		CLK_CEC_LSE
-		CLK_I2C12_HSI
-		CLK_I2C35_HSI
-		CLK_UART1_HSI
 		CLK_UART24_HSI
-		CLK_UART35_HSI
-		CLK_UART6_HSI
-		CLK_UART78_HSI
-		CLK_SPDIF_PLL4P
-		CLK_FDCAN_PLL4R
-		CLK_SAI1_PLL3Q
-		CLK_SAI2_PLL3Q
-		CLK_SAI3_PLL3Q
-		CLK_SAI4_PLL3Q
-		CLK_RNG1_CSI
-		CLK_RNG2_LSI
-		CLK_LPTIM1_PCLK1
-		CLK_LPTIM23_PCLK3
-		CLK_LPTIM45_LSE
 	>;
 
 	st,clkdiv = <
@@ -248,8 +216,6 @@
 		DIV(DIV_APB4, 1)
 		DIV(DIV_APB5, 2)
 		DIV(DIV_RTC, 23)
-		DIV(DIV_MCO1, 0)
-		DIV(DIV_MCO2, 0)
 	>;
 
 	st,pll_vco {
diff --git a/fdts/tc-base.dtsi b/fdts/tc-base.dtsi
index fc0b3b6..ac08e0b 100644
--- a/fdts/tc-base.dtsi
+++ b/fdts/tc-base.dtsi
@@ -104,28 +104,6 @@
 			};
 		};
 
-		amus {
-			amu: amu-0 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-
-				mpmm_gear0: counter@0 {
-					reg = <0>;
-					enable-at-el3;
-				};
-
-				mpmm_gear1: counter@1 {
-					reg = <1>;
-					enable-at-el3;
-				};
-
-				mpmm_gear2: counter@2 {
-					reg = <2>;
-					enable-at-el3;
-				};
-			};
-		};
-
 		CPU0:cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,armv8";
@@ -134,8 +112,6 @@
 			clocks = <&scmi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <LIT_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU1:cpu@100 {
@@ -146,8 +122,6 @@
 			clocks = <&scmi_dvfs 0>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <LIT_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU2:cpu@200 {
@@ -156,8 +130,6 @@
 			reg = <0x200>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU3:cpu@300 {
@@ -166,8 +138,6 @@
 			reg = <0x300>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU4:cpu@400 {
@@ -178,8 +148,6 @@
 			clocks = <&scmi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <MID_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU5:cpu@500 {
@@ -190,8 +158,6 @@
 			clocks = <&scmi_dvfs 1>;
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
 			capacity-dmips-mhz = <MID_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU6:cpu@600 {
@@ -200,8 +166,6 @@
 			reg = <0x600>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU7:cpu@700 {
@@ -210,8 +174,6 @@
 			reg = <0x700>;
 			enable-method = "psci";
 			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 	};
 
diff --git a/fdts/tc2.dts b/fdts/tc2.dts
index 8aa77ce..fa16dcd 100644
--- a/fdts/tc2.dts
+++ b/fdts/tc2.dts
@@ -123,8 +123,6 @@
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 1>;
 			capacity-dmips-mhz = <MID_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU9:cpu@900 {
@@ -134,8 +132,6 @@
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 2>;
 			capacity-dmips-mhz = <BIG2_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU10:cpu@A00 {
@@ -145,8 +141,6 @@
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 2>;
 			capacity-dmips-mhz = <BIG2_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU11:cpu@B00 {
@@ -156,8 +150,6 @@
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 2>;
 			capacity-dmips-mhz = <BIG2_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU12:cpu@C00 {
@@ -167,8 +159,6 @@
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 3>;
 			capacity-dmips-mhz = <BIG_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 
 		CPU13:cpu@D00 {
@@ -178,8 +168,6 @@
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 3>;
 			capacity-dmips-mhz = <BIG_CAPACITY>;
-			amu = <&amu>;
-			supports-mpmm;
 		};
 #endif
 	};
diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
index d2591dd..41be1a1 100644
--- a/include/arch/aarch32/arch.h
+++ b/include/arch/aarch32/arch.h
@@ -761,7 +761,7 @@
 
 /* AMCNTENSET0 definitions */
 #define AMCNTENSET0_Pn_SHIFT	U(0)
-#define AMCNTENSET0_Pn_MASK	U(0xffff)
+#define AMCNTENSET0_Pn_MASK	U(0xf)
 
 /* AMCNTENSET1 definitions */
 #define AMCNTENSET1_Pn_SHIFT	U(0)
@@ -769,7 +769,7 @@
 
 /* AMCNTENCLR0 definitions */
 #define AMCNTENCLR0_Pn_SHIFT	U(0)
-#define AMCNTENCLR0_Pn_MASK	U(0xffff)
+#define AMCNTENCLR0_Pn_MASK	U(0xf)
 
 /* AMCNTENCLR1 definitions */
 #define AMCNTENCLR1_Pn_SHIFT	U(0)
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
index e347240..e80faf2 100644
--- a/include/arch/aarch32/arch_features.h
+++ b/include/arch/aarch32/arch_features.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -85,6 +85,10 @@
 CREATE_FEATURE_FUNCS(feat_amu, id_pfr0, ID_PFR0_AMU_SHIFT,
 		    ID_PFR0_AMU_MASK, ID_PFR0_AMU_V1, ENABLE_FEAT_AMU)
 
+/* Auxiliary counters for FEAT_AMU */
+CREATE_FEATURE_FUNCS(feat_amu_aux, amcfgr, AMCFGR_NCG_SHIFT,
+		    AMCFGR_NCG_MASK, 1U, ENABLE_AMU_AUXILIARY_COUNTERS)
+
 /* FEAT_AMUV1P1: AMU Extension v1.1 */
 CREATE_FEATURE_FUNCS(feat_amuv1p1, id_pfr0, ID_PFR0_AMU_SHIFT,
 		    ID_PFR0_AMU_MASK, ID_PFR0_AMU_V1P1, ENABLE_FEAT_AMUv1p1)
diff --git a/include/arch/aarch32/arch_helpers.h b/include/arch/aarch32/arch_helpers.h
index adc96ae..4f80e3a 100644
--- a/include/arch/aarch32/arch_helpers.h
+++ b/include/arch/aarch32/arch_helpers.h
@@ -324,6 +324,23 @@
 DEFINE_COPROCR_RW_FUNCS_64(amevcntr02, AMEVCNTR02)
 DEFINE_COPROCR_RW_FUNCS_64(amevcntr03, AMEVCNTR03)
 
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr10, AMEVCNTR10);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr11, AMEVCNTR11);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr12, AMEVCNTR12);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr13, AMEVCNTR13);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr14, AMEVCNTR14);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr15, AMEVCNTR15);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr16, AMEVCNTR16);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr17, AMEVCNTR17);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr18, AMEVCNTR18);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr19, AMEVCNTR19);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr1a, AMEVCNTR1A);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr1b, AMEVCNTR1B);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr1c, AMEVCNTR1C);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr1d, AMEVCNTR1D);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr1e, AMEVCNTR1E);
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr1f, AMEVCNTR1F);
+
 /*
  * TLBI operation prototypes
  */
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index dfa2f97..85b33aa 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1141,6 +1141,7 @@
  ******************************************************************************/
 #define ID_AA64SMFR0_EL1		S3_0_C0_C4_5
 #define SMCR_EL3			S3_6_C1_C2_6
+#define SVCR				S3_3_C4_C2_2
 
 /* ID_AA64SMFR0_EL1 definitions */
 #define ID_AA64SMFR0_EL1_SME_FA64_SHIFT		U(63)
@@ -1529,6 +1530,11 @@
 #define SCTLR2_EL1		S3_0_C1_C0_3
 
 /*******************************************************************************
+ * FEAT_BRBE - Branch Record Buffer Extension Registers
+ ******************************************************************************/
+#define BRBCR_EL2		S2_4_C9_C0_0
+
+/*******************************************************************************
  * FEAT_LS64_ACCDATA - LoadStore64B with status data
  ******************************************************************************/
 #define ACCDATA_EL1		S3_0_C13_C0_5
@@ -1554,12 +1560,10 @@
  ******************************************************************************/
 
 #define CPUPPMCR_EL3			S3_6_C15_C2_0
-#define CPUPPMCR_EL3_MPMMPINCTL_SHIFT	UINT64_C(0)
-#define CPUPPMCR_EL3_MPMMPINCTL_MASK	UINT64_C(0x1)
+#define CPUPPMCR_EL3_MPMMPINCTL_BIT	BIT(0)
 
 #define CPUMPMMCR_EL3			S3_6_C15_C2_1
-#define CPUMPMMCR_EL3_MPMM_EN_SHIFT	UINT64_C(0)
-#define CPUMPMMCR_EL3_MPMM_EN_MASK	UINT64_C(0x1)
+#define CPUMPMMCR_EL3_MPMM_EN_BIT	BIT(0)
 
 /* alternative system register encoding for the "sb" speculation barrier */
 #define SYSREG_SB			S0_3_C3_C0_7
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 1d0a2e0..a580213 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -311,6 +311,10 @@
 CREATE_FEATURE_FUNCS(feat_amu, id_aa64pfr0_el1, ID_AA64PFR0_AMU_SHIFT,
 		     ID_AA64PFR0_AMU_MASK, 1U, ENABLE_FEAT_AMU)
 
+/* Auxiliary counters for FEAT_AMU */
+CREATE_FEATURE_FUNCS(feat_amu_aux, amcfgr_el0, AMCFGR_EL0_NCG_SHIFT,
+		     AMCFGR_EL0_NCG_MASK, 1U, ENABLE_AMU_AUXILIARY_COUNTERS)
+
 /* FEAT_AMUV1P1: AMU Extension v1.1 */
 CREATE_FEATURE_FUNCS(feat_amuv1p1, id_aa64pfr0_el1, ID_AA64PFR0_AMU_SHIFT,
 		     ID_AA64PFR0_AMU_MASK, ID_AA64PFR0_AMU_V1P1, ENABLE_FEAT_AMUv1p1)
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 8b92f19..f85da97 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -564,6 +564,27 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset0_el0, AMCNTENSET0_EL0)
 DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0)
 DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset1_el0, AMCNTENSET1_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr00_el0, AMEVCNTR00_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr01_el0, AMEVCNTR01_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr02_el0, AMEVCNTR02_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr03_el0, AMEVCNTR03_EL0);
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr10_el0, AMEVCNTR10_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr11_el0, AMEVCNTR11_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr12_el0, AMEVCNTR12_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr13_el0, AMEVCNTR13_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr14_el0, AMEVCNTR14_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr15_el0, AMEVCNTR15_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr16_el0, AMEVCNTR16_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr17_el0, AMEVCNTR17_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr18_el0, AMEVCNTR18_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr19_el0, AMEVCNTR19_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr1a_el0, AMEVCNTR1A_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr1b_el0, AMEVCNTR1B_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr1c_el0, AMEVCNTR1C_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr1d_el0, AMEVCNTR1D_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr1e_el0, AMEVCNTR1E_EL0);
+DEFINE_RENAME_SYSREG_RW_FUNCS(amevcntr1f_el0, AMEVCNTR1F_EL0);
 
 DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1)
 
@@ -572,6 +593,7 @@
 
 DEFINE_RENAME_IDREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el3, SMCR_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(svcr, SVCR)
 
 DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
 DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1)
@@ -715,6 +737,9 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(cpumpmmcr_el3, CPUMPMMCR_EL3)
 
+/* Armv9.1 FEAT_BRBE Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbcr_el2, BRBCR_EL2)
+
 /* Armv9.2 RME Registers */
 DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
diff --git a/include/arch/aarch64/asm_macros.S b/include/arch/aarch64/asm_macros.S
index ff01278..dce07d9 100644
--- a/include/arch/aarch64/asm_macros.S
+++ b/include/arch/aarch64/asm_macros.S
@@ -8,6 +8,7 @@
 
 #include <arch.h>
 #include <common/asm_macros_common.S>
+#include <lib/cpus/cpu_ops.h>
 #include <lib/spinlock.h>
 
 /*
@@ -340,4 +341,26 @@
 	mrs	\reg, ID_AA64ISAR2_EL1
 	ands	\reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT)
 	.endm
+
+.macro call_reset_handler
+#if !(defined(IMAGE_BL2) && ENABLE_RME)
+	/* ---------------------------------------------------------------------
+	 * It is a cold boot.
+	 * Perform any processor specific actions upon reset e.g. cache, TLB
+	 * invalidations etc.
+	 * ---------------------------------------------------------------------
+	 */
+	/* The plat_reset_handler can clobber x0 - x18, x30 */
+	bl	plat_reset_handler
+
+	/* Get the matching cpu_ops pointer */
+	bl	get_cpu_ops_ptr
+
+	/* Get the cpu_ops reset handler */
+	ldr	x2, [x0, #CPU_RESET_FUNC]
+
+	/* The cpu_ops reset handler can clobber x0 - x19, x30 */
+	blr	x2
+#endif
+.endm
 #endif /* ASM_MACROS_S */
diff --git a/include/arch/aarch64/el2_common_macros.S b/include/arch/aarch64/el2_common_macros.S
index b9b0e3d..5db6831 100644
--- a/include/arch/aarch64/el2_common_macros.S
+++ b/include/arch/aarch64/el2_common_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -293,7 +293,7 @@
 	 * invalidations etc.
 	 * ---------------------------------------------------------------------
 	 */
-	bl	reset_handler
+	call_reset_handler
 
 	el2_arch_init_common
 
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
index 204625c..2f2aeaf 100644
--- a/include/arch/aarch64/el3_common_macros.S
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -49,7 +49,9 @@
 	 * due to a NULL TPIDR_EL3.
 	 * ---------------------------------------------------------------------
 	 */
-	bl	init_cpu_data_ptr
+	bl	plat_my_core_pos
+	bl	_cpu_data_by_index
+	msr	tpidr_el3, x0
 #endif /* IMAGE_BL31 */
 
 	/* ---------------------------------------------------------------------
@@ -219,15 +221,7 @@
 	msr	vbar_el3, x0
 	isb
 
-#if !(defined(IMAGE_BL2) && ENABLE_RME)
-	/* ---------------------------------------------------------------------
-	 * It is a cold boot.
-	 * Perform any processor specific actions upon reset e.g. cache, TLB
-	 * invalidations etc.
-	 * ---------------------------------------------------------------------
-	 */
-	bl	reset_handler
-#endif
+	call_reset_handler
 
 	el3_arch_init_common
 
@@ -460,6 +454,10 @@
 	 *  Necessary on PMUv3 <= p7 where MDCR_EL3.{SCCD,MCCD} are not
 	 *  available.
 	 *
+	 * CPTR_EL3.EZ: Set to one so that accesses to ZCR_EL3 do not trap
+	 * CPTR_EL3.TFP: Set to zero so that advanced SIMD operations don't trap
+	 * CPTR_EL3.ESM: Set to one so that SME related registers don't trap
+	 *
 	 * PSTATE.DIT: Set to one to enable the Data Independent Timing (DIT)
 	 *  functionality, if implemented in EL3.
 	 * ---------------------------------------------------------------------
@@ -479,6 +477,12 @@
 		orr	x15, x15, #PMCR_EL0_DP_BIT
 		msr	pmcr_el0, x15
 
+		mrs	x15, cptr_el3
+		orr	x15, x15, #CPTR_EZ_BIT
+		orr	x15, x15, #ESM_BIT
+		bic	x15, x15, #TFP_BIT
+		msr	cptr_el3, x15
+
 #if ENABLE_FEAT_DIT
 #if ENABLE_FEAT_DIT > 1
 		mrs	x15, id_aa64pfr0_el1
diff --git a/include/common/fdt_wrappers.h b/include/common/fdt_wrappers.h
index de08f1d..7f6af59 100644
--- a/include/common/fdt_wrappers.h
+++ b/include/common/fdt_wrappers.h
@@ -49,6 +49,8 @@
 
 int fdtw_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
 
+uint64_t fdt_read_prop_cells(const fdt32_t *prop, int nr_cells);
+
 static inline uint32_t fdt_blob_size(const void *dtb)
 {
 	const uint32_t *dtb_header = (const uint32_t *)dtb;
diff --git a/include/drivers/arm/css/css_scp.h b/include/drivers/arm/css/css_scp.h
index 2b506ea..5395546 100644
--- a/include/drivers/arm/css/css_scp.h
+++ b/include/drivers/arm/css/css_scp.h
@@ -22,9 +22,9 @@
 void css_scp_off(const struct psci_power_state *target_state);
 void css_scp_on(u_register_t mpidr);
 int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level);
-void __dead2 css_scp_sys_shutdown(void);
-void __dead2 css_scp_sys_reboot(void);
-void __dead2 css_scp_system_off(int state);
+void css_scp_sys_shutdown(void);
+void css_scp_sys_reboot(void);
+void css_scp_system_off(int state);
 
 /* API for SCP Boot Image transfer. Return 0 on success, -1 on error */
 int css_scp_boot_image_xfer(void *image, unsigned int image_size);
diff --git a/include/drivers/arm/gic600_multichip.h b/include/drivers/arm/gic600_multichip.h
index 978d735..d0f9027 100644
--- a/include/drivers/arm/gic600_multichip.h
+++ b/include/drivers/arm/gic600_multichip.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
  * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -49,10 +49,10 @@
  * value of {0, 0, 0} should be passed.
  ******************************************************************************/
 struct gic600_multichip_data {
-	uintptr_t rt_owner_base;
+	uintptr_t base_addrs[GIC600_MAX_MULTICHIP];
 	unsigned int rt_owner;
 	unsigned int chip_count;
-	uint64_t chip_addrs[GIC600_MAX_MULTICHIP];
+	uint64_t chip_addrs[GIC600_MAX_MULTICHIP][GIC600_MAX_MULTICHIP];
 	multichip_spi_ids_desc_t spi_ids[GIC600_MAX_MULTICHIP];
 };
 
diff --git a/include/drivers/arm/mhu.h b/include/drivers/arm/mhu.h
index 31c6a81..cc74e27 100644
--- a/include/drivers/arm/mhu.h
+++ b/include/drivers/arm/mhu.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,6 +26,14 @@
 };
 
 /**
+ * Structure used by RSE comms
+ */
+struct mhu_addr {
+	uintptr_t sender_base;
+	uintptr_t receiver_base;
+};
+
+/**
  * Initializes sender MHU.
  *
  * mhu_sender_base	Base address of sender MHU.
diff --git a/include/drivers/arm/rse_comms.h b/include/drivers/arm/rse_comms.h
index e4169a5..43c8b70 100644
--- a/include/drivers/arm/rse_comms.h
+++ b/include/drivers/arm/rse_comms.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -8,8 +8,12 @@
 #ifndef RSE_COMMS_H
 #define RSE_COMMS_H
 
+#include <stddef.h>
 #include <stdint.h>
 
-int rse_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base);
+size_t rse_mbx_get_max_message_size(void);
+int rse_mbx_send_data(const uint8_t *send_buffer, size_t size);
+int rse_mbx_receive_data(uint8_t *receive_buffer, size_t *size);
+int rse_mbx_init(const void *init_data);
 
 #endif /* RSE_COMMS_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
index d34dc22..63716e8 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: BSD-3-Clause */
 /*
- * Copyright 2024 NXP
+ * Copyright 2024-2025 NXP
  */
 #ifndef S32CC_CLK_IDS_H
 #define S32CC_CLK_IDS_H
@@ -103,4 +103,8 @@
 #define S32CC_CLK_MC_CGM5_MUX0			S32CC_ARCH_CLK(20)
 #define S32CC_CLK_DDR				S32CC_ARCH_CLK(21)
 
+/* USDHC clock */
+#define S32CC_CLK_MC_CGM0_MUX14			S32CC_ARCH_CLK(22)
+#define S32CC_CLK_USDHC				S32CC_ARCH_CLK(23)
+
 #endif /* S32CC_CLK_IDS_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
index c91f3b6..285aeb3 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
@@ -19,6 +19,7 @@
 	s32cc_pll_out_div_t,
 	s32cc_dfs_t,
 	s32cc_dfs_div_t,
+	s32cc_cgm_div_t,
 	s32cc_clkmux_t,
 	s32cc_shared_clkmux_t,
 	s32cc_fixed_div_t,
@@ -37,6 +38,7 @@
 	S32CC_CGM0,
 	S32CC_CGM1,
 	S32CC_DDR_PLL,
+	S32CC_PERIPH_DFS,
 	S32CC_CGM5,
 };
 
@@ -287,6 +289,22 @@
 	.block = (BLOCK),                        \
 }
 
+struct s32cc_cgm_div {
+	struct s32cc_clk_obj desc;
+	struct s32cc_clk_obj *parent;
+	unsigned long freq;
+	uint32_t index;
+};
+
+#define S32CC_CGM_DIV_INIT(PARENT, INDEX) \
+{                                         \
+	.desc = {                         \
+		.type = s32cc_cgm_div_t,  \
+	},                                \
+	.parent = &(PARENT).desc,         \
+	.index = (INDEX),                 \
+}
+
 static inline struct s32cc_osc *s32cc_obj2osc(const struct s32cc_clk_obj *mod)
 {
 	uintptr_t osc_addr;
@@ -399,4 +417,12 @@
 	return (struct s32cc_part_block_link *)blk_link;
 }
 
+static inline struct s32cc_cgm_div *s32cc_obj2cgmdiv(const struct s32cc_clk_obj *mod)
+{
+	uintptr_t cgm_div_addr;
+
+	cgm_div_addr = ((uintptr_t)mod) - offsetof(struct s32cc_cgm_div, desc);
+	return (struct s32cc_cgm_div *)cgm_div_addr;
+}
+
 #endif /* S32CC_CLK_MODULES_H */
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S
index cfa5831..31f8811 100644
--- a/include/lib/cpus/aarch32/cpu_macros.S
+++ b/include/lib/cpus/aarch32/cpu_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -48,8 +48,7 @@
 	 * _midr:
 	 *	Numeric value expected to read from CPU's MIDR
 	 * _resetfunc:
-	 *	Reset function for the CPU. If there's no CPU reset function,
-	 *	specify CPU_NO_RESET_FUNC
+	 *	Reset function for the CPU
 	 * _power_down_ops:
 	 *	Comma-separated list of functions to perform power-down
 	 *	operatios on the CPU. At least one, and up to
@@ -173,11 +172,6 @@
 		\_cpu\()_errata_list_start:
 		.endif
 
-		/* unused on AArch32, maintain for portability */
-		.word	0
-		/* TODO(errata ABI): this prevents all checker functions from
-		 * being optimised away. Can be done away with unless the ABI
-		 * needs them */
 		.ifnb \_special
 			.word	check_errata_\_special
 		.elseif \_cve
@@ -189,9 +183,7 @@
 		.word	\_id
 		.hword	\_cve
 		.byte	\_chosen
-		/* TODO(errata ABI): mitigated field for known but unmitigated
-		 * errata*/
-		.byte	0x1
+		.byte	0x0 /* alignment */
 	.popsection
 .endm
 
diff --git a/include/lib/cpus/aarch64/cortex_a320.h b/include/lib/cpus/aarch64/cortex_a320.h
new file mode 100644
index 0000000..5231151
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a320.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A320_H
+#define CORTEX_A320_H
+
+#define CORTEX_A320_MIDR					U(0x410FD8F0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A320_CPUECTLR_EL1				S3_0_C15_C1_4
+#define CORTEX_A320_CPUECTLR_EL1_EXTLLC_BIT			U(0)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_A320_CPUPWRCTLR_EL1				S3_0_C15_C2_7
+#define CORTEX_A320_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
+
+#endif /* CORTEX_A320_H */
diff --git a/include/lib/cpus/aarch64/cortex_alto.h b/include/lib/cpus/aarch64/cortex_alto.h
index 1c8786a..9e2929f 100644
--- a/include/lib/cpus/aarch64/cortex_alto.h
+++ b/include/lib/cpus/aarch64/cortex_alto.h
@@ -20,10 +20,4 @@
 #define CORTEX_ALTO_IMP_CPUPWRCTLR_EL1				S3_0_C15_C2_7
 #define CORTEX_ALTO_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT	U(1)
 
-/*******************************************************************************
- * SME Control registers
- ******************************************************************************/
-#define CORTEX_ALTO_SVCRSM					S0_3_C4_C2_3
-#define CORTEX_ALTO_SVCRZA					S0_3_C4_C4_3
-
 #endif /* CORTEX_ALTO_H */
diff --git a/include/lib/cpus/aarch64/cortex_arcadia.h b/include/lib/cpus/aarch64/cortex_arcadia.h
deleted file mode 100644
index 8b74de2..0000000
--- a/include/lib/cpus/aarch64/cortex_arcadia.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef CORTEX_ARCADIA_H
-#define CORTEX_ARCADIA_H
-
-#define CORTEX_ARCADIA_MIDR					U(0x410FD8F0)
-
-/*******************************************************************************
- * CPU Extended Control register specific definitions
- ******************************************************************************/
-#define CORTEX_ARCADIA_CPUECTLR_EL1				S3_0_C15_C1_4
-#define CORTEX_ARCADIA_CPUECTLR_EL1_EXTLLC_BIT			U(0)
-
-/*******************************************************************************
- * CPU Power Control register specific definitions
- ******************************************************************************/
-#define CORTEX_ARCADIA_CPUPWRCTLR_EL1				S3_0_C15_C2_7
-#define CORTEX_ARCADIA_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
-
-#endif /* CORTEX_ARCADIA_H */
diff --git a/include/lib/cpus/aarch64/cortex_gelas.h b/include/lib/cpus/aarch64/cortex_gelas.h
index 486b868..9024faf 100644
--- a/include/lib/cpus/aarch64/cortex_gelas.h
+++ b/include/lib/cpus/aarch64/cortex_gelas.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -23,10 +23,4 @@
 #define CORTEX_GELAS_CPUPWRCTLR_EL1			S3_0_C15_C2_7
 #define CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT	U(1)
 
-/*******************************************************************************
- * SME Control registers
- ******************************************************************************/
-#define CORTEX_GELAS_SVCRSM				S0_3_C4_C2_3
-#define CORTEX_GELAS_SVCRZA				S0_3_C4_C4_3
-
 #endif /* CORTEX_GELAS_H */
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
index 0ce9c3c..a43746f 100644
--- a/include/lib/cpus/aarch64/cpu_macros.S
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -49,8 +49,7 @@
 	 * _midr:
 	 *	Numeric value expected to read from CPU's MIDR
 	 * _resetfunc:
-	 *	Reset function for the CPU. If there's no CPU reset function,
-	 *	specify CPU_NO_RESET_FUNC
+	 *	Reset function for the CPU.
 	 * _extra1:
 	 *	This is a placeholder for future per CPU operations.  Currently,
 	 *	some CPUs use this entry to set a test function to determine if
@@ -239,50 +238,22 @@
  * _apply_at_reset:
  *	Whether the erratum should be automatically applied at reset
  */
-.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
+.macro add_erratum_entry _cpu:req, _cve:req, _id:req, _chosen:req
+#if REPORT_ERRATA || ERRATA_ABI_SUPPORT
 	.pushsection .rodata.errata_entries
 		.align	3
 		.ifndef \_cpu\()_errata_list_start
 		\_cpu\()_errata_list_start:
 		.endif
 
-		/* check if unused and compile out if no references */
-		.if \_apply_at_reset && \_chosen
-			.quad	erratum_\_cpu\()_\_id\()_wa
-		.else
-			.quad	0
-		.endif
-		/* TODO(errata ABI): this prevents all checker functions from
-		 * being optimised away. Can be done away with unless the ABI
-		 * needs them */
 		.quad	check_erratum_\_cpu\()_\_id
 		/* Will fit CVEs with up to 10 character in the ID field */
 		.word	\_id
 		.hword	\_cve
 		.byte	\_chosen
-		/* TODO(errata ABI): mitigated field for known but unmitigated
-		 * errata */
-		.byte	0x1
+		.byte	0x0 /* alignment */
 	.popsection
-.endm
-
-.macro _workaround_start _cpu:req, _cve:req, _id:req, _chosen:req, _apply_at_reset:req
-	add_erratum_entry \_cpu, \_cve, \_id, \_chosen, \_apply_at_reset
-
-	func erratum_\_cpu\()_\_id\()_wa
-		mov	x8, x30
-
-		/* save rev_var for workarounds that might need it but don't
-		 * restore to x0 because few will care */
-		mov	x7, x0
-		bl	check_erratum_\_cpu\()_\_id
-		cbz	x0, erratum_\_cpu\()_\_id\()_skip
-.endm
-
-.macro _workaround_end _cpu:req, _id:req
-	erratum_\_cpu\()_\_id\()_skip:
-		ret	x8
-	endfunc erratum_\_cpu\()_\_id\()_wa
+#endif
 .endm
 
 /*******************************************************************************
@@ -312,7 +283,22 @@
  * _wa clobbers: x0-x8 (PCS compliant)
  */
 .macro workaround_reset_start _cpu:req, _cve:req, _id:req, _chosen:req
-	_workaround_start \_cpu, \_cve, \_id, \_chosen, 1
+	add_erratum_entry \_cpu, \_cve, \_id, \_chosen
+
+	.if \_chosen
+		/* put errata directly into the reset function */
+		.pushsection .text.asm.\_cpu\()_reset_func, "ax"
+	.else
+		/* or something else that will get garbage collected by the
+		 * linker */
+		.pushsection .text.asm.erratum_\_cpu\()_\_id\()_wa, "ax"
+	.endif
+		/* revision is stored in x14, get it */
+		mov	x0, x14
+		bl	check_erratum_\_cpu\()_\_id
+		/* save rev_var for workarounds that might need it */
+		mov	x7, x14
+		cbz	x0, erratum_\_cpu\()_\_id\()_skip_reset
 .endm
 
 /*
@@ -323,6 +309,10 @@
  *	for errata applied in generic code
  */
 .macro workaround_runtime_start _cpu:req, _cve:req, _id:req, _chosen:req, _midr
+	add_erratum_entry \_cpu, \_cve, \_id, \_chosen
+
+	func erratum_\_cpu\()_\_id\()_wa
+		mov	x8, x30
 	/*
 	 * Let errata specify if they need MIDR checking. Sadly, storing the
 	 * MIDR in an .equ to retrieve automatically blows up as it stores some
@@ -330,11 +320,15 @@
 	 */
 	.ifnb \_midr
 		jump_if_cpu_midr \_midr, 1f
-		b	erratum_\_cpu\()_\_id\()_skip
+		b	erratum_\_cpu\()_\_id\()_skip_runtime
 
 		1:
 	.endif
-	_workaround_start \_cpu, \_cve, \_id, \_chosen, 0
+		/* save rev_var for workarounds that might need it but don't
+		 * restore to x0 because few will care */
+		mov	x7, x0
+		bl	check_erratum_\_cpu\()_\_id
+		cbz	x0, erratum_\_cpu\()_\_id\()_skip_runtime
 .endm
 
 /*
@@ -342,7 +336,8 @@
  * is kept here so the same #define can be used as that macro
  */
 .macro workaround_reset_end _cpu:req, _cve:req, _id:req
-	_workaround_end \_cpu, \_id
+	erratum_\_cpu\()_\_id\()_skip_reset:
+	.popsection
 .endm
 
 /*
@@ -362,7 +357,9 @@
 	.ifb \_no_isb
 		isb
 	.endif
-	_workaround_end \_cpu, \_id
+	erratum_\_cpu\()_\_id\()_skip_runtime:
+		ret	x8
+	endfunc erratum_\_cpu\()_\_id\()_wa
 .endm
 
 /*******************************************************************************
@@ -402,6 +399,18 @@
 	msr	\_reg, x1
 .endm
 
+/*
+ * Toggle a bit in a system register. Can toggle multiple bits but is limited by
+ *  the way the EOR instrucion encodes them.
+ *
+ * see sysreg_bit_set for usage
+ */
+.macro sysreg_bit_toggle _reg:req, _bit:req, _assert=1
+	mrs	x1, \_reg
+	eor	x1, x1, #\_bit
+	msr	\_reg, x1
+.endm
+
 .macro override_vector_table _table:req
 	adr	x1, \_table
 	msr	vbar_el3, x1
@@ -429,6 +438,29 @@
 .endm
 
 /*
+ * Extract CPU revision and variant, and combine them into a single numeric for
+ * easier comparison.
+ *
+ * _res:
+ *	register where the result will be placed
+ * _tmp:
+ *	register to clobber for temporaries
+ */
+.macro get_rev_var _res:req, _tmp:req
+	mrs	\_tmp, midr_el1
+
+	/*
+	 * Extract the variant[23:20] and revision[3:0] from MIDR, and pack them
+	 * as variant[7:4] and revision[3:0] of x0.
+	 *
+	 * First extract x1[23:16] to x0[7:0] and zero fill the rest. Then
+	 * extract x1[3:0] into x0[3:0] retaining other bits.
+	 */
+	ubfx	\_res, \_tmp, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
+	bfxil	\_res, \_tmp, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+.endm
+
+/*
  * Apply erratum
  *
  * _cpu:
@@ -451,7 +483,7 @@
  * clobbers: x0-x10 (PCS compliant)
  */
 .macro apply_erratum _cpu:req, _cve:req, _id:req, _chosen:req, _get_rev=GET_CPU_REV
-	.if (\_chosen & \_get_rev)
+	.if (\_chosen && \_get_rev)
 		mov	x9, x30
 		bl	cpu_get_rev_var
 		mov	x10, x0
@@ -467,8 +499,35 @@
 .endm
 
 /*
- * Helpers to select which revisions errata apply to. Don't leave a link
- * register as the cpu_rev_var_*** will call the ret and we can save on one.
+ * Helpers to report if an erratum applies. Compares the given revision variant
+ * to the given value. Return ERRATA_APPLIES or ERRATA_NOT_APPLIES accordingly.
+ *
+ * _rev_num: the given revision variant. Or
+ * _rev_num_lo,_rev_num_hi: the lower and upper bounds of the revision variant
+ *
+ * in body:
+ *	clobber: x0
+ *	argument: x0 - cpu_rev_var
+ */
+.macro cpu_rev_var_ls _rev_num:req
+	cmp	x0, #\_rev_num
+	cset	x0, ls
+.endm
+
+.macro cpu_rev_var_hs _rev_num:req
+	cmp	x0, #\_rev_num
+	cset	x0, hs
+.endm
+
+.macro cpu_rev_var_range _rev_num_lo:req, _rev_num_hi:req
+	cmp	x0, #\_rev_num_lo
+	mov	x1, #\_rev_num_hi
+	ccmp	x0, x1, #2, hs
+	cset	x0, ls
+.endm
+
+/*
+ * Helpers to select which revisions errata apply to.
  *
  * _cpu:
  *	Name of cpu as given to declare_cpu_ops
@@ -484,28 +543,27 @@
  *	Revision to apply to
  *
  * in body:
- *	clobber: x0 to x4
+ *	clobber: x0 to x1
  *	argument: x0 - cpu_rev_var
  */
 .macro check_erratum_ls _cpu:req, _cve:req, _id:req, _rev_num:req
 	func check_erratum_\_cpu\()_\_id
-		mov	x1, #\_rev_num
-		b	cpu_rev_var_ls
+		cpu_rev_var_ls \_rev_num
+		ret
 	endfunc check_erratum_\_cpu\()_\_id
 .endm
 
 .macro check_erratum_hs _cpu:req, _cve:req, _id:req, _rev_num:req
 	func check_erratum_\_cpu\()_\_id
-		mov	x1, #\_rev_num
-		b	cpu_rev_var_hs
+		cpu_rev_var_hs \_rev_num
+		ret
 	endfunc check_erratum_\_cpu\()_\_id
 .endm
 
 .macro check_erratum_range _cpu:req, _cve:req, _id:req, _rev_num_lo:req, _rev_num_hi:req
 	func check_erratum_\_cpu\()_\_id
-		mov	x1, #\_rev_num_lo
-		mov	x2, #\_rev_num_hi
-		b	cpu_rev_var_range
+		cpu_rev_var_range \_rev_num_lo, \_rev_num_hi
+		ret
 	endfunc check_erratum_\_cpu\()_\_id
 .endm
 
@@ -520,7 +578,10 @@
 	endfunc check_erratum_\_cpu\()_\_id
 .endm
 
-/* provide a shorthand for the name format for annoying errata */
+/*
+ * provide a shorthand for the name format for annoying errata
+ * body: clobber x0 to x4
+ */
 .macro check_erratum_custom_start _cpu:req, _cve:req, _id:req
 	func check_erratum_\_cpu\()_\_id
 .endm
@@ -535,7 +596,21 @@
  ******************************************************************************/
 
 /*
+ * Helper to register a cpu with the errata framework. Begins the definition of
+ * the reset function.
+ *
+ * _cpu:
+ *	Name of cpu as given to declare_cpu_ops
+ */
+.macro cpu_reset_prologue _cpu:req
+	func \_cpu\()_reset_func
+		mov	x15, x30
+		get_rev_var x14, x0
+.endm
+
+/*
- * Wrapper to automatically apply all reset-time errata. Will end with an isb.
+ * Wrapper of the reset function to automatically apply all reset-time errata.
+ * Will end with an isb.
  *
  * _cpu:
  *	Name of cpu as given to declare_cpu_ops
@@ -545,39 +620,9 @@
  *	argument x14 - cpu_rev_var
  */
 .macro cpu_reset_func_start _cpu:req
-	func \_cpu\()_reset_func
-		mov	x15, x30
-		bl	cpu_get_rev_var
-		mov	x14, x0
-
-		/* short circuit the location to avoid searching the list */
-		adrp	x12, \_cpu\()_errata_list_start
-		add	x12, x12, :lo12:\_cpu\()_errata_list_start
-		adrp	x13, \_cpu\()_errata_list_end
-		add	x13, x13, :lo12:\_cpu\()_errata_list_end
-
-	errata_begin:
-		/* if head catches up with end of list, exit */
-		cmp	x12, x13
-		b.eq	errata_end
-
-		ldr	x10, [x12, #ERRATUM_WA_FUNC]
-		/* TODO(errata ABI): check mitigated and checker function fields
-		 * for 0 */
-		ldrb	w11, [x12, #ERRATUM_CHOSEN]
-
-		/* skip if not chosen */
-		cbz	x11, 1f
-		/* skip if runtime erratum */
-		cbz	x10, 1f
-
-		/* put cpu revision in x0 and call workaround */
-		mov	x0, x14
-		blr	x10
-	1:
-		add	x12, x12, #ERRATUM_ENTRY_SIZE
-		b	errata_begin
-	errata_end:
+	/* the func/endfunc macros will change sections. So change the section
+	 * back to the reset function's */
+	.section .text.asm.\_cpu\()_reset_func, "ax"
 .endm
 
 .macro cpu_reset_func_end _cpu:req
@@ -586,4 +631,21 @@
 	endfunc \_cpu\()_reset_func
 .endm
 
+/*
+ * Helper macro that enables Maximum Power Mitigation Mechanism (MPMM) on
+ * compatible Arm cores.
+ *
+ * Clobbers x0.
+ */
+.macro enable_mpmm
+#if ENABLE_MPMM
+	mrs	x0, CPUPPMCR_EL3
+	/* if CPUPPMCR_EL3.MPMMPINCTL != 0, skip enabling MPMM */
+	ands	x0, x0, CPUPPMCR_EL3_MPMMPINCTL_BIT
+	b.ne	1f
+	sysreg_bit_set CPUPPMCR_EL3, CPUMPMMCR_EL3_MPMM_EN_BIT
+	1:
+#endif
+.endm
+
 #endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/aarch64/dsu_def.h b/include/lib/cpus/aarch64/dsu_def.h
index 51fbfd1..78b3e7f 100644
--- a/include/lib/cpus/aarch64/dsu_def.h
+++ b/include/lib/cpus/aarch64/dsu_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -40,7 +40,23 @@
  ********************************************************************/
 #define DSU_ERRATA_936184_MASK	(U(0x3) << 15)
 
+#define CPUCFR_EL1		S3_0_C15_C0_0
+/* SCU bit of CPU Configuration Register, EL1 */
+#define SCU_SHIFT		U(2)
+
 #ifndef __ASSEMBLER__
-void dsu_pwr_dwn(void);
+DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrctlr_el1, CLUSTERPWRCTLR_EL1);
+
+/* ---------------------------------------------
+ * controls power features of the cluster
+ * 1. Cache portion power not request
+ * 2. Disable the retention circuit
+ * ---------------------------------------------
+ */
+static inline void dsu_pwr_dwn(void)
+{
+	write_clusterpwrctlr_el1(0);
+	isb();
+}
 #endif
 #endif /* DSU_DEF_H */
diff --git a/include/lib/cpus/aarch64/dsu_macros.S b/include/lib/cpus/aarch64/dsu_macros.S
new file mode 100644
index 0000000..6c8cb69
--- /dev/null
+++ b/include/lib/cpus/aarch64/dsu_macros.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019-2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DSU_MACROS_S
+#define DSU_MACROS_S
+
+#include <asm_macros.S>
+#include <dsu_def.h>
+#include <lib/cpus/errata.h>
+
+.macro check_errata_dsu_798953_impl
+	mov	x2, #ERRATA_APPLIES
+	mov	x3, #ERRATA_NOT_APPLIES
+
+	/* Check if DSU is equal to r0p0 */
+	mrs	x1, CLUSTERIDR_EL1
+
+	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
+	ubfx	x0, x1, #CLUSTERIDR_REV_SHIFT,\
+			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
+	mov	x1, #(0x0 << CLUSTERIDR_REV_SHIFT)
+	cmp	x0, x1
+	csel	x0, x2, x3, EQ
+.endm
+
+.macro errata_dsu_798953_wa_impl
+	/* If erratum applies, disable high-level clock gating */
+	mrs	x0, CLUSTERACTLR_EL1
+	orr	x0, x0, #CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING
+	msr	CLUSTERACTLR_EL1, x0
+.endm
+
+.macro branch_if_scu_not_present _target:req
+	/* Check if the SCU L3 Unit is present on the DSU */
+	mrs	x0, CPUCFR_EL1
+	ubfx	x0, x0, #SCU_SHIFT, #1
+	eor	x0, x0, #1
+	/* If SCU is not present, return without applying patch */
+	cmp	x0, xzr
+	mov	x0, #ERRATA_NOT_APPLIES
+	b.eq	\_target
+.endm
+
+.macro check_errata_dsu_936184_impl
+	mov	x0, #ERRATA_NOT_APPLIES
+	/* Erratum applies only if DSU has the ACP interface */
+	mrs	x1, CLUSTERCFR_EL1
+	ubfx	x1, x1, #CLUSTERCFR_ACP_SHIFT, #1
+	cbz	x1, 1f
+
+	/* If ACP is present, check if DSU is older than r2p0 */
+	mrs	x1, CLUSTERIDR_EL1
+
+	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
+	ubfx	x2, x1, #CLUSTERIDR_REV_SHIFT,\
+			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
+	cmp x2, #(0x2 << CLUSTERIDR_VAR_SHIFT)
+	b.hs	1f
+	mov	x0, #ERRATA_APPLIES
+1:
+.endm
+
+.macro errata_dsu_936184_wa_impl
+	/* If erratum applies, we set a mask to a DSU control register */
+	mrs	x0, CLUSTERACTLR_EL1
+	ldr	x1, =DSU_ERRATA_936184_MASK
+	orr	x0, x0, x1
+	msr	CLUSTERACTLR_EL1, x0
+.endm
+
+.macro check_errata_dsu_2313941_impl
+	mov	x2, #ERRATA_APPLIES
+	mov	x3, #ERRATA_NOT_APPLIES
+
+	/* Check if DSU version is less than or equal to r3p1 */
+	mrs	x1, CLUSTERIDR_EL1
+
+	mov	x0, #ERRATA_NOT_APPLIES
+	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
+	ubfx	x0, x1, #CLUSTERIDR_REV_SHIFT,\
+			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
+	mov	x1, #(0x31 << CLUSTERIDR_REV_SHIFT)
+	cmp	x0, x1
+	csel	x0, x2, x3, LS
+1:
+.endm
+
+.macro errata_dsu_2313941_wa_impl
+	/* If erratum applies, disable high-level clock gating */
+	mrs	x0, CLUSTERACTLR_EL1
+	orr	x0, x0, #CLUSTERACTLR_EL1_DISABLE_SCLK_GATING
+	msr	CLUSTERACTLR_EL1, x0
+.endm
+#endif /* DSU_MACROS_S */
diff --git a/include/lib/cpus/aarch64/neoverse_n_common.h b/include/lib/cpus/aarch64/neoverse_n_common.h
deleted file mode 100644
index 7cb91cd..0000000
--- a/include/lib/cpus/aarch64/neoverse_n_common.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef NEOVERSE_N_COMMON_H
-#define NEOVERSE_N_COMMON_H
-
-/******************************************************************************
- * Neoverse Nx CPU Configuration register definitions
- *****************************************************************************/
-#define CPUCFR_EL1		S3_0_C15_C0_0
-
-/* SCU bit of CPU Configuration Register, EL1 */
-#define SCU_SHIFT		U(2)
-
-#endif /* NEOVERSE_N_COMMON_H */
diff --git a/include/lib/cpus/aarch64/travis.h b/include/lib/cpus/aarch64/travis.h
index a8a2556..b622ea0 100644
--- a/include/lib/cpus/aarch64/travis.h
+++ b/include/lib/cpus/aarch64/travis.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -20,10 +20,4 @@
 #define TRAVIS_IMP_CPUPWRCTLR_EL1			S3_0_C15_C2_7
 #define TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT	U(1)
 
-/*******************************************************************************
- * SME Control registers
- ******************************************************************************/
-#define TRAVIS_SVCRSM					S0_3_C4_C2_3
-#define TRAVIS_SVCRZA					S0_3_C4_C4_3
-
 #endif /* TRAVIS_H */
diff --git a/include/lib/cpus/cpu_ops.h b/include/lib/cpus/cpu_ops.h
index c1bdf8d..0b08919 100644
--- a/include/lib/cpus/cpu_ops.h
+++ b/include/lib/cpus/cpu_ops.h
@@ -21,8 +21,6 @@
 
 /* The number of CPU operations allowed */
 #define CPU_MAX_PWR_DWN_OPS		2
-/* Special constant to specify that CPU has no reset function */
-#define CPU_NO_RESET_FUNC		0
 
 #if __aarch64__
 #define CPU_NO_EXTRA1_FUNC		0
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
index b9166f7..10b949f 100644
--- a/include/lib/cpus/errata.h
+++ b/include/lib/cpus/errata.h
@@ -9,20 +9,18 @@
 
 #include <lib/cpus/cpu_ops.h>
 
-#define ERRATUM_WA_FUNC_SIZE	CPU_WORD_SIZE
 #define ERRATUM_CHECK_FUNC_SIZE	CPU_WORD_SIZE
 #define ERRATUM_ID_SIZE		4
 #define ERRATUM_CVE_SIZE	2
 #define ERRATUM_CHOSEN_SIZE	1
-#define ERRATUM_MITIGATED_SIZE	1
+#define ERRATUM_ALIGNMENT_SIZE	1
 
-#define ERRATUM_WA_FUNC		0
-#define ERRATUM_CHECK_FUNC	ERRATUM_WA_FUNC + ERRATUM_WA_FUNC_SIZE
+#define ERRATUM_CHECK_FUNC	0
 #define ERRATUM_ID		ERRATUM_CHECK_FUNC + ERRATUM_CHECK_FUNC_SIZE
 #define ERRATUM_CVE		ERRATUM_ID + ERRATUM_ID_SIZE
 #define ERRATUM_CHOSEN		ERRATUM_CVE + ERRATUM_CVE_SIZE
-#define ERRATUM_MITIGATED	ERRATUM_CHOSEN + ERRATUM_CHOSEN_SIZE
-#define ERRATUM_ENTRY_SIZE	ERRATUM_MITIGATED + ERRATUM_MITIGATED_SIZE
+#define ERRATUM_ALIGNMENT	ERRATUM_CHOSEN + ERRATUM_CHOSEN_SIZE
+#define ERRATUM_ENTRY_SIZE	ERRATUM_ALIGNMENT + ERRATUM_ALIGNMENT_SIZE
 
 /* Errata status */
 #define ERRATA_NOT_APPLIES	0
@@ -39,15 +37,13 @@
  * uintptr_t will reflect the change and the alignment will be correct in both.
  */
 struct erratum_entry {
-	uintptr_t (*wa_func)(uint64_t cpu_rev);
 	uintptr_t (*check_func)(uint64_t cpu_rev);
 	/* Will fit CVEs with up to 10 character in the ID field */
 	uint32_t id;
 	/* Denote CVEs with their year or errata with 0 */
 	uint16_t cve;
 	uint8_t chosen;
-	/* TODO(errata ABI): placeholder for the mitigated field */
-	uint8_t _mitigated;
+	uint8_t _alignment;
 } __packed;
 
 CASSERT(sizeof(struct erratum_entry) == ERRATUM_ENTRY_SIZE,
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 87f1541..d9a9188 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -67,25 +67,25 @@
  ******************************************************************************/
 #define CTX_EL3STATE_OFFSET	(CTX_GPREGS_OFFSET + CTX_GPREGS_END)
 #define CTX_SCR_EL3		U(0x0)
-#define CTX_ESR_EL3		U(0x8)
-#define CTX_RUNTIME_SP		U(0x10)
-#define CTX_SPSR_EL3		U(0x18)
-#define CTX_ELR_EL3		U(0x20)
-#define CTX_PMCR_EL0		U(0x28)
-#define CTX_IS_IN_EL3		U(0x30)
-#define CTX_MDCR_EL3		U(0x38)
+#define CTX_RUNTIME_SP		U(0x8)
+#define CTX_SPSR_EL3		U(0x10)
+#define CTX_ELR_EL3		U(0x18)
+#define CTX_PMCR_EL0		U(0x20)
+#define CTX_IS_IN_EL3		U(0x28)
+#define CTX_MDCR_EL3		U(0x30)
 /* Constants required in supporting nested exception in EL3 */
-#define CTX_SAVED_ELR_EL3	U(0x40)
+#define CTX_SAVED_ELR_EL3	U(0x38)
 /*
  * General purpose flag, to save various EL3 states
  * FFH mode : Used to identify if handling nested exception
  * KFH mode : Used as counter value
  */
-#define CTX_NESTED_EA_FLAG	U(0x48)
+#define CTX_NESTED_EA_FLAG	U(0x40)
 #if FFH_SUPPORT
- #define CTX_SAVED_ESR_EL3	U(0x50)
- #define CTX_SAVED_SPSR_EL3	U(0x58)
- #define CTX_SAVED_GPREG_LR	U(0x60)
+ #define CTX_SAVED_ESR_EL3	U(0x48)
+ #define CTX_SAVED_SPSR_EL3	U(0x50)
+ #define CTX_SAVED_GPREG_LR	U(0x58)
+ #define CTX_DOUBLE_FAULT_ESR	U(0x60)
  #define CTX_EL3STATE_END	U(0x70) /* Align to the next 16 byte boundary */
 #else
  #define CTX_EL3STATE_END	U(0x50) /* Align to the next 16 byte boundary */
@@ -167,9 +167,8 @@
  * Registers initialised in a per-world context.
  ******************************************************************************/
 #define CTX_CPTR_EL3			U(0x0)
-#define CTX_ZCR_EL3			U(0x8)
-#define CTX_MPAM3_EL3			U(0x10)
-#define CTX_PERWORLD_EL3STATE_END	U(0x18)
+#define CTX_MPAM3_EL3			U(0x8)
+#define CTX_PERWORLD_EL3STATE_END	U(0x10)
 
 #ifndef __ASSEMBLER__
 
@@ -278,7 +277,6 @@
  */
 typedef struct per_world_context {
 	uint64_t ctx_cptr_el3;
-	uint64_t ctx_zcr_el3;
 	uint64_t ctx_mpam3_el3;
 } per_world_context_t;
 
diff --git a/include/lib/el3_runtime/context_el2.h b/include/lib/el3_runtime/context_el2.h
index f35a091..672f533 100644
--- a/include/lib/el3_runtime/context_el2.h
+++ b/include/lib/el3_runtime/context_el2.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -142,6 +142,10 @@
 	uint64_t sctlr2_el2;
 } el2_sctlr2_regs_t;
 
+typedef struct el2_brbe_regs {
+	uint64_t brbcr_el2;
+} el2_brbe_regs_t;
+
 typedef struct el2_sysregs {
 
 	el2_common_regs_t common;
@@ -214,6 +218,10 @@
 	el2_sctlr2_regs_t sctlr2;
 #endif
 
+#if ENABLE_BRBE_FOR_NS
+	el2_brbe_regs_t brbe;
+#endif
+
 } el2_sysregs_t;
 
 /*
@@ -384,6 +392,15 @@
 #define write_el2_ctx_sctlr2(ctx, reg, val)
 #endif /* ENABLE_FEAT_SCTLR2 */
 
+#if ENABLE_BRBE_FOR_NS
+#define read_el2_ctx_brbe(ctx, reg)		(((ctx)->brbe).reg)
+#define write_el2_ctx_brbe(ctx, reg, val)	((((ctx)->brbe).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_brbe(ctx, reg)		ULL(0)
+#define write_el2_ctx_brbe(ctx, reg, val)
+#endif /* ENABLE_BRBE_FOR_NS */
+
 /******************************************************************************/
 
 #endif /* __ASSEMBLER__ */
diff --git a/include/lib/el3_runtime/context_mgmt.h b/include/lib/el3_runtime/context_mgmt.h
index 70dbd46..a48ed96 100644
--- a/include/lib/el3_runtime/context_mgmt.h
+++ b/include/lib/el3_runtime/context_mgmt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -41,7 +41,7 @@
 
 #ifdef __aarch64__
 #if IMAGE_BL31
-void cm_manage_extensions_el3(void);
+void cm_manage_extensions_el3(unsigned int my_idx);
 void manage_extensions_nonsecure_per_world(void);
 void cm_el3_arch_init_per_world(per_world_context_t *per_world_ctx);
 void cm_handle_asymmetric_features(void);
@@ -95,7 +95,7 @@
 #else
 void *cm_get_next_context(void);
 void cm_set_next_context(void *context);
-static inline void cm_manage_extensions_el3(void) {}
+static inline void cm_manage_extensions_el3(unsigned int cpu_idx) {}
 static inline void manage_extensions_nonsecure_per_world(void) {}
 static inline void cm_handle_asymmetric_features(void) {}
 #endif /* __aarch64__ */
diff --git a/include/lib/el3_runtime/cpu_data.h b/include/lib/el3_runtime/cpu_data.h
index 8b54806..e417f45 100644
--- a/include/lib/el3_runtime/cpu_data.h
+++ b/include/lib/el3_runtime/cpu_data.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -230,7 +230,6 @@
  * APIs for initialising and accessing per-cpu data
  *************************************************************************/
 
-void init_cpu_data_ptr(void);
 void init_cpu_ops(void);
 
 #define get_cpu_data(_m)		   _cpu_data()->_m
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
index a396b99..4020331 100644
--- a/include/lib/extensions/amu.h
+++ b/include/lib/extensions/amu.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,7 +17,7 @@
 #if ENABLE_FEAT_AMU
 #if __aarch64__
 void amu_enable(cpu_context_t *ctx);
-void amu_init_el3(void);
+void amu_init_el3(unsigned int core_pos);
 void amu_init_el2_unused(void);
 void amu_enable_per_world(per_world_context_t *per_world_ctx);
 #else
@@ -29,7 +29,7 @@
 void amu_enable(cpu_context_t *ctx)
 {
 }
-void amu_init_el3(void)
+void amu_init_el3(unsigned int core_pos)
 {
 }
 void amu_init_el2_unused(void)
@@ -45,28 +45,57 @@
 #endif /*__aarch64__ */
 #endif /* ENABLE_FEAT_AMU */
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
 /*
- * AMU data for a single core.
+ * Per-core list of the counters to be enabled. Value will be written into
+ * AMCNTENSET1_EL0 verbatim.
  */
-struct amu_core {
-	uint16_t enable; /* Mask of auxiliary counters to enable */
-};
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+extern uint16_t plat_amu_aux_enables[PLATFORM_CORE_COUNT];
+#endif
 
-/*
- * Topological platform data specific to the AMU.
- */
-struct amu_topology {
-	struct amu_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */
-};
+#define CTX_AMU_GRP0_ALL		U(4)
+#define CTX_AMU_GRP1_ALL		U(16)
 
-#if !ENABLE_AMU_FCONF
-/*
- * Retrieve the platform's AMU topology. A `NULL` return value is treated as a
- * non-fatal error, in which case no auxiliary counters will be enabled.
- */
-const struct amu_topology *plat_amu_topology(void);
-#endif /* ENABLE_AMU_FCONF */
-#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
+typedef struct amu_regs {
+	u_register_t grp0[CTX_AMU_GRP0_ALL];
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	u_register_t grp1[CTX_AMU_GRP1_ALL];
+#endif
+} amu_regs_t;
+
+static inline u_register_t read_amu_grp0_ctx_reg(amu_regs_t *ctx, size_t index)
+{
+	return ctx->grp0[index];
+}
+
+static inline void write_amu_grp0_ctx_reg(amu_regs_t *ctx, size_t index, u_register_t val)
+{
+	ctx->grp0[index] = val;
+}
+
+static inline uint16_t get_amu_aux_enables(size_t index)
+{
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	return plat_amu_aux_enables[index];
+#else
+	return 0;
+#endif
+}
+
+static inline u_register_t read_amu_grp1_ctx_reg(amu_regs_t *ctx, size_t index)
+{
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	return ctx->grp1[index];
+#else
+	return 0;
+#endif
+}
+
+static inline void write_amu_grp1_ctx_reg(amu_regs_t *ctx, size_t index, u_register_t val)
+{
+#if ENABLE_AMU_AUXILIARY_COUNTERS
+	ctx->grp1[index] = val;
+#endif
+}
 
 #endif /* AMU_H */
diff --git a/include/lib/extensions/ras_arch.h b/include/lib/extensions/ras_arch.h
index e0aee50..fb2d526 100644
--- a/include/lib/extensions/ras_arch.h
+++ b/include/lib/extensions/ras_arch.h
@@ -143,14 +143,16 @@
 /* Uncorrected error types for Asynchronous exceptions */
 #define ERROR_STATUS_UET_UC	0x0	/* Uncontainable */
 #define ERROR_STATUS_UET_UEU	0x1	/* Unrecoverable */
-#define ERROR_STATUS_UET_UEO	0x2	/* Restable */
+#define ERROR_STATUS_UET_UEO	0x2	/* Restartable */
 #define ERROR_STATUS_UET_UER	0x3	/* Recoverable */
 
+/* Corrected error types for Asynchronous exceptions */
+#define ERROR_STATUS_CET_CE	0x6	/* Corrected (CE) */
+
 /* Error types for Synchronous exceptions */
 #define ERROR_STATUS_SET_UER	0x0	/* Recoverable */
-#define ERROR_STATUS_SET_UEO	0x1	/* Restable */
 #define ERROR_STATUS_SET_UC	0x2     /* Uncontainable */
-#define ERROR_STATUS_SET_CE	0x3     /* Corrected */
+#define ERROR_STATUS_SET_UEO	0x3     /* Restartable */
 
 /* Number of architecturally-defined primary error codes */
 #define ERROR_STATUS_NUM_SERR	U(22)
@@ -176,6 +178,9 @@
 #define EABORT_SET_WIDTH	U(2)
 #define EABORT_SET_MASK		U(0x3)
 
+#define EABORT_GET_FIELD(_esr_el3, _field) \
+	(((_esr_el3) >> EABORT_ ##_field ##_SHIFT) & EABORT_ ##_field ##_MASK)
+
 /* DFSC code for SErrors */
 #define DFSC_SERROR		0x11
 
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
index 2979efb..a471efb 100644
--- a/include/lib/extensions/sve.h
+++ b/include/lib/extensions/sve.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,10 +11,14 @@
 
 #if (ENABLE_SME_FOR_NS || ENABLE_SVE_FOR_NS)
 
+void sve_init_el3(void);
 void sve_init_el2_unused(void);
 void sve_enable_per_world(per_world_context_t *per_world_ctx);
 void sve_disable_per_world(per_world_context_t *per_world_ctx);
 #else
+static inline void sve_init_el3(void)
+{
+}
 static inline void sve_init_el2_unused(void)
 {
 }
diff --git a/include/lib/fconf/fconf_amu_getter.h b/include/lib/fconf/fconf_amu_getter.h
deleted file mode 100644
index 2faee73..0000000
--- a/include/lib/fconf/fconf_amu_getter.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FCONF_AMU_GETTER_H
-#define FCONF_AMU_GETTER_H
-
-#include <lib/extensions/amu.h>
-
-#define amu__config_getter(id)	fconf_amu_config.id
-
-struct fconf_amu_config {
-	const struct amu_topology *topology;
-};
-
-extern struct fconf_amu_config fconf_amu_config;
-
-#endif /* FCONF_AMU_GETTER_H */
diff --git a/include/lib/fconf/fconf_mpmm_getter.h b/include/lib/fconf/fconf_mpmm_getter.h
deleted file mode 100644
index 50d991a..0000000
--- a/include/lib/fconf/fconf_mpmm_getter.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef FCONF_MPMM_GETTER_H
-#define FCONF_MPMM_GETTER_H
-
-#include <lib/mpmm/mpmm.h>
-
-#define mpmm__config_getter(id)	fconf_mpmm_config.id
-
-struct fconf_mpmm_config {
-	const struct mpmm_topology *topology;
-};
-
-extern struct fconf_mpmm_config fconf_mpmm_config;
-
-#endif /* FCONF_MPMM_GETTER_H */
diff --git a/include/lib/gpt_rme/gpt_rme.h b/include/lib/gpt_rme/gpt_rme.h
index 94a88b0..135a948 100644
--- a/include/lib/gpt_rme/gpt_rme.h
+++ b/include/lib/gpt_rme/gpt_rme.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,13 +8,20 @@
 #define GPT_RME_H
 
 #include <stdint.h>
-
-#include <arch.h>
+#include <lib/spinlock.h>
 
 /******************************************************************************/
 /* GPT helper macros and definitions                                          */
 /******************************************************************************/
 
+#if (RME_GPT_BITLOCK_BLOCK != 0)
+#define LOCK_SIZE	sizeof(((bitlock_t *)NULL)->lock)
+#define LOCK_TYPE	typeof(((bitlock_t *)NULL)->lock)
+#define LOCK_BITS	(LOCK_SIZE * UL(8))
+
+CASSERT((UL(1) == LOCK_SIZE), assert_bitlock_type_not_uint8_t);
+#endif /* RME_GPT_BITLOCK_BLOCK */
+
 /*
  * Structure for specifying a mapping range and it's properties. This should not
  * be manually initialized, using the MAP_GPT_REGION_x macros is recommended as
@@ -238,10 +245,14 @@
  * initialization from a previous stage. Granule protection checks must be
  * enabled already or this function will return an error.
  *
+ * Parameters
+ *   l1_bitlocks_base	Base address of memory for L1 tables bitlocks.
+ *   l1_bitlocks_size	Total size of memory available for L1 tables bitlocks.
+ *
  * Return
  *   Negative Linux error code in the event of a failure, 0 for success.
  */
-int gpt_runtime_init(void);
+int gpt_runtime_init(uintptr_t l1_bitlocks_base, size_t l1_bitlocks_size);
 
 /*
  * Public API to enable granule protection checks once the tables have all been
diff --git a/include/lib/libc/cdefs.h b/include/lib/libc/cdefs.h
index b11d072..97b7824 100644
--- a/include/lib/libc/cdefs.h
+++ b/include/lib/libc/cdefs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -36,4 +36,7 @@
 #define __STRING(x)	#x
 #define __XSTRING(x)	__STRING(x)
 
+#define __predict_true(exp)     (exp)
+#define __predict_false(exp)    (exp)
+
 #endif /* CDEFS_H */
diff --git a/include/lib/libc/stdlib.h b/include/lib/libc/stdlib.h
index 4e5a824..71bb4ba 100644
--- a/include/lib/libc/stdlib.h
+++ b/include/lib/libc/stdlib.h
@@ -29,4 +29,6 @@
 unsigned long strtoul(const char *nptr, char **endptr, int base);
 long long strtoll(const char *nptr, char **endptr, int base);
 unsigned long long strtoull(const char *nptr, char **endptr, int base);
+void qsort(void *, size_t, size_t,
+           int (*)(const void *, const void *));
 #endif /* STDLIB_H */
diff --git a/include/lib/mpmm/mpmm.h b/include/lib/mpmm/mpmm.h
deleted file mode 100644
index 955c530..0000000
--- a/include/lib/mpmm/mpmm.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef MPMM_H
-#define MPMM_H
-
-#include <stdbool.h>
-
-#include <platform_def.h>
-
-/*
- * Enable the Maximum Power Mitigation Mechanism.
- *
- * This function will enable MPMM for the current core. The AMU counters
- * representing the MPMM gears must have been configured and enabled prior to
- * calling this function.
- */
-void mpmm_enable(void);
-
-/*
- * MPMM core data.
- *
- * This structure represents per-core data retrieved from the hardware
- * configuration device tree.
- */
-struct mpmm_core {
-	/*
-	 * Whether MPMM is supported.
-	 *
-	 * Cores with support for MPMM offer one or more auxiliary AMU counters
-	 * representing MPMM gears.
-	 */
-	bool supported;
-};
-
-/*
- * MPMM topology.
- *
- * This topology structure describes the system-wide representation of the
- * information retrieved from the hardware configuration device tree.
- */
-struct mpmm_topology {
-	struct mpmm_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */
-};
-
-#if !ENABLE_MPMM_FCONF
-/*
- * Retrieve the platform's MPMM topology. A `NULL` return value is treated as a
- * non-fatal error, in which case MPMM will not be enabled for any core.
- */
-const struct mpmm_topology *plat_mpmm_topology(void);
-#endif /* ENABLE_MPMM_FCONF */
-
-#endif /* MPMM_H */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index f12a4d6..68e721a 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -331,10 +331,10 @@
 				const psci_power_state_t *target_state);
 	void (*pwr_domain_suspend_finish)(
 				const psci_power_state_t *target_state);
-	void __dead2 (*pwr_domain_pwr_down_wfi)(
+	void (*pwr_domain_pwr_down)(
 				const psci_power_state_t *target_state);
-	void __dead2 (*system_off)(void);
-	void __dead2 (*system_reset)(void);
+	void (*system_off)(void);
+	void (*system_reset)(void);
 	int (*validate_power_state)(unsigned int power_state,
 				    psci_power_state_t *req_state);
 	int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
@@ -376,7 +376,7 @@
 #if PSCI_OS_INIT_MODE
 int psci_set_suspend_mode(unsigned int mode);
 #endif
-void __dead2 psci_power_down_wfi(void);
+void psci_power_down_wfi(void);
 void psci_arch_setup(void);
 
 #endif /*__ASSEMBLER__*/
diff --git a/include/lib/psci/psci_lib.h b/include/lib/psci/psci_lib.h
index 9950a6e..8c9296b 100644
--- a/include/lib/psci/psci_lib.h
+++ b/include/lib/psci/psci_lib.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -94,6 +94,9 @@
 bool psci_is_last_on_cpu_safe(unsigned int this_core);
 bool psci_are_all_cpus_on_safe(unsigned int this_core);
 void psci_pwrdown_cpu(unsigned int power_level);
+void psci_pwrdown_cpu_start(unsigned int power_level);
+void __dead2 psci_pwrdown_cpu_end_terminal(void);
+void psci_pwrdown_cpu_end_wakeup(unsigned int power_level);
 void psci_do_manage_extensions(void);
 
 #endif /* __ASSEMBLER__ */
diff --git a/include/lib/transfer_list.h b/include/lib/transfer_list.h
index bcf9fc9..c403031 100644
--- a/include/lib/transfer_list.h
+++ b/include/lib/transfer_list.h
@@ -110,6 +110,7 @@
 
 CASSERT(sizeof(struct transfer_list_entry) == U(0x8), assert_transfer_list_entry_size);
 
+void transfer_entry_dump(struct transfer_list_entry *te);
 void transfer_list_dump(struct transfer_list_header *tl);
 struct transfer_list_header *transfer_list_ensure(void *addr, size_t size);
 entry_point_info_t *
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 3ce6a91..cc1dcde 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -20,7 +20,6 @@
  * Definitions common to all ARM standard platforms
  *****************************************************************************/
 
-
 /* Special value used to verify platform parameters from BL2 to BL31 */
 #define ARM_BL31_PLAT_PARAM_VAL		ULL(0x0f1e2d3c4b5a6978)
 
@@ -63,11 +62,22 @@
 #define ARM_SHARED_RAM_BASE		ARM_TRUSTED_SRAM_BASE
 #define ARM_SHARED_RAM_SIZE		UL(0x00001000)	/* 4 KB */
 
+#if ENABLE_RME
+/* Store level 0 GPT at the top of the Trusted SRAM */
+#define ARM_L0_GPT_BASE			(ARM_TRUSTED_SRAM_BASE + \
+					 PLAT_ARM_TRUSTED_SRAM_SIZE - \
+					 ARM_L0_GPT_SIZE)
+#define ARM_L0_GPT_SIZE			UL(0x00002000)	/* 8 KB */
+#else
+#define ARM_L0_GPT_SIZE			UL(0)
+#endif
+
 /* The remaining Trusted SRAM is used to load the BL images */
-#define ARM_BL_RAM_BASE			(ARM_SHARED_RAM_BASE +	\
+#define ARM_BL_RAM_BASE			(ARM_SHARED_RAM_BASE + \
 					 ARM_SHARED_RAM_SIZE)
-#define ARM_BL_RAM_SIZE			(PLAT_ARM_TRUSTED_SRAM_SIZE -	\
-					 ARM_SHARED_RAM_SIZE)
+#define ARM_BL_RAM_SIZE			(PLAT_ARM_TRUSTED_SRAM_SIZE - \
+					 ARM_SHARED_RAM_SIZE - \
+					 ARM_L0_GPT_SIZE)
 
 /*
  * The top 16MB (or 64MB if RME is enabled) of DRAM1 is configured as
@@ -110,6 +120,7 @@
  * placed here. 3MB region is reserved if RME is enabled, 2MB otherwise.
  */
 #define ARM_EL3_TZC_DRAM1_SIZE		UL(0x00300000) /* 3MB */
+/* 8 x 128KB L1 pages (L0GPTSZ = 1GB, PGS = 4KB) */
 #define ARM_L1_GPT_SIZE			UL(0x00100000) /* 1MB */
 /* 32MB - ARM_EL3_RMM_SHARED_SIZE */
 #define ARM_REALM_SIZE			(UL(0x02000000) -		\
@@ -150,7 +161,7 @@
 #endif /* (SPD_tspd || SPD_opteed || SPD_spmd) && MEASURED_BOOT */
 
 #if ENABLE_RME
-#define ARM_L1_GPT_BASE		(ARM_DRAM1_BASE +		\
+#define ARM_L1_GPT_BASE			(ARM_DRAM1_BASE +		\
 					ARM_DRAM1_SIZE -		\
 					ARM_L1_GPT_SIZE)
 #define ARM_L1_GPT_END			(ARM_L1_GPT_BASE +		\
@@ -246,6 +257,9 @@
 /* Number of DRAM banks */
 #define ARM_DRAM_NUM_BANKS		2UL
 
+/* Number of PCIe memory regions */
+#define ARM_PCI_NUM_REGIONS		2UL
+
 #define ARM_IRQ_SEC_PHY_TIMER		29
 
 #define ARM_IRQ_SEC_SGI_0		8
@@ -352,7 +366,6 @@
 					ARM_EL3_RMM_SHARED_BASE,	\
 					ARM_EL3_RMM_SHARED_SIZE,	\
 					MT_MEMORY | MT_RW | MT_REALM)
-
 #endif /* ENABLE_RME */
 
 /*
@@ -540,18 +553,6 @@
 #define ARM_FW_CONFIGS_LIMIT		(ARM_BL_RAM_BASE + ARM_FW_CONFIGS_SIZE)
 #endif
 
-#if ENABLE_RME
-/*
- * Store the L0 GPT on Trusted SRAM next to firmware
- * configuration memory, 4KB aligned.
- */
-#define ARM_L0_GPT_SIZE			(PAGE_SIZE)
-#define ARM_L0_GPT_BASE		(ARM_FW_CONFIGS_LIMIT)
-#define ARM_L0_GPT_LIMIT		(ARM_L0_GPT_BASE + ARM_L0_GPT_SIZE)
-#else
-#define ARM_L0_GPT_SIZE			U(0)
-#endif
-
 /*******************************************************************************
  * BL1 specific defines.
  * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
@@ -567,7 +568,8 @@
 #endif
 
 /*
- * Put BL1 RW at the top of the Trusted SRAM.
+ * With ENABLE_RME=1 put BL1 RW below L0 GPT,
+ * or at the top of Trusted SRAM otherwise.
  */
 #define BL1_RW_BASE			(ARM_BL_RAM_BASE +		\
 						ARM_BL_RAM_SIZE -	\
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
index 84e6b38..d5a3c42 100644
--- a/include/plat/arm/css/common/css_pm.h
+++ b/include/plat/arm/css/common/css_pm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,8 +35,8 @@
 void css_pwr_domain_suspend(const psci_power_state_t *target_state);
 void css_pwr_domain_suspend_finish(
 				const psci_power_state_t *target_state);
-void __dead2 css_system_off(void);
-void __dead2 css_system_reset(void);
+void css_system_off(void);
+void css_system_reset(void);
 void css_cpu_standby(plat_local_state_t cpu_state);
 void css_get_sys_suspend_power_state(psci_power_state_t *req_state);
 int css_node_hw_state(u_register_t mpidr, unsigned int power_level);
diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h
index ecec5bc..3cfab4f 100644
--- a/include/plat/common/common_def.h
+++ b/include/plat/common/common_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -43,6 +43,11 @@
 
 #define SZ_1G				UL(0x40000000)
 #define SZ_2G				UL(0x80000000)
+
+#define SZ_1T				UL(0x10000000000)
+#define SZ_4T				UL(0x40000000000)
+
+#define SZ_1P				UL(0x4000000000000)
 #else /* !__aarch64__ */
 #define SZ_32				U(0x00000020)
 #define SZ_64				U(0x00000040)
diff --git a/include/plat/common/plat_drtm.h b/include/plat/common/plat_drtm.h
index 07545a6..0d6a818 100644
--- a/include/plat/common/plat_drtm.h
+++ b/include/plat/common/plat_drtm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -59,6 +59,8 @@
 uint64_t plat_drtm_get_tcb_hash_table_size(void);
 uint64_t plat_drtm_get_imp_def_dlme_region_size(void);
 uint64_t plat_drtm_get_tcb_hash_features(void);
+uint64_t plat_drtm_get_acpi_tables_region_size(void);
+uint64_t plat_drtm_get_dlme_img_auth_features(void);
 
 /* DRTM error handling functions */
 int plat_set_drtm_error(uint64_t error_code);
diff --git a/include/services/drtm_svc.h b/include/services/drtm_svc.h
index f0d3c63..3503fa4 100644
--- a/include/services/drtm_svc.h
+++ b/include/services/drtm_svc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024 Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier:    BSD-3-Clause
  *
@@ -49,6 +49,7 @@
 #define ARM_DRTM_FEATURES_DMA_PROT	U(0x3)
 #define ARM_DRTM_FEATURES_BOOT_PE_ID	U(0x4)
 #define ARM_DRTM_FEATURES_TCB_HASHES	U(0x5)
+#define ARM_DRTM_FEATURES_DLME_IMG_AUTH	U(0x6)
 
 #define is_drtm_fid(_fid) \
 	(((_fid) >= ARM_DRTM_SVC_VERSION) && ((_fid) <= ARM_DRTM_SVC_LOCK_TCB_HASH))
@@ -109,6 +110,9 @@
 #define ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_SHIFT	U(0)
 #define ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_MASK	ULL(0xFF)
 
+#define ARM_DRTM_DLME_IMAGE_AUTH_SUPPORT_SHIFT	U(0)
+#define ARM_DRTM_DLME_IMAGE_AUTH_SUPPORT_MASK	ULL(0x1)
+
 #define ARM_DRTM_TPM_FEATURES_SET_PCR_SCHEMA(reg, val)			\
 	do {								\
 		reg = (((reg) & ~(ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_MASK \
@@ -178,6 +182,16 @@
 		ARM_DRTM_TCB_HASH_FEATURES_MAX_NUM_HASHES_SHIFT));	\
 	} while (false)
 
+#define ARM_DRTM_DLME_IMG_AUTH_SUPPORT(reg, val)		\
+	do {								\
+		reg = (((reg) &						\
+		~(ARM_DRTM_DLME_IMAGE_AUTH_SUPPORT_MASK <<	\
+		ARM_DRTM_DLME_IMAGE_AUTH_SUPPORT_SHIFT)) |	\
+		(((val) &						\
+		ARM_DRTM_DLME_IMAGE_AUTH_SUPPORT_MASK) <<	\
+		ARM_DRTM_DLME_IMAGE_AUTH_SUPPORT_SHIFT));	\
+	} while (false)
+
 /* Definitions for DRTM address map */
 #define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_SHIFT	U(55)
 #define ARM_DRTM_REGION_SIZE_TYPE_CACHEABILITY_MASK	ULL(0x3)
diff --git a/include/services/rmm_core_manifest.h b/include/services/rmm_core_manifest.h
index 6b57267..2d6e71f 100644
--- a/include/services/rmm_core_manifest.h
+++ b/include/services/rmm_core_manifest.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,7 +14,7 @@
 #include <lib/cassert.h>
 
 #define RMMD_MANIFEST_VERSION_MAJOR		U(0)
-#define RMMD_MANIFEST_VERSION_MINOR		U(3)
+#define RMMD_MANIFEST_VERSION_MINOR		U(4)
 
 #define RMM_CONSOLE_MAX_NAME_LEN		U(8)
 
@@ -37,29 +37,29 @@
 #define RMMD_GET_MANIFEST_VERSION_MINOR(_version)		\
 	(_version & 0xFFFF)
 
-/* NS DRAM bank structure */
-struct ns_dram_bank {
+/* Memory bank/device region structure */
+struct memory_bank {
 	uintptr_t base;			/* Base address */
-	uint64_t size;			/* Size of bank */
+	uint64_t size;			/* Size of memory bank/device region */
 };
 
-CASSERT(offsetof(struct ns_dram_bank, base) == 0UL,
+CASSERT(offsetof(struct memory_bank, base) == 0UL,
 			rmm_manifest_base_unaligned);
-CASSERT(offsetof(struct ns_dram_bank, size) == 8UL,
+CASSERT(offsetof(struct memory_bank, size) == 8UL,
 			rmm_manifest_size_unaligned);
 
-/* NS DRAM layout info structure */
-struct ns_dram_info {
-	uint64_t num_banks;		/* Number of NS DRAM banks */
-	struct ns_dram_bank *banks;	/* Pointer to ns_dram_bank[] */
-	uint64_t checksum;		/* Checksum of ns_dram_info data */
+/* Memory/device region layout info structure */
+struct memory_info {
+	uint64_t num_banks;		/* Number of memory banks/device regions */
+	struct memory_bank *banks;	/* Pointer to memory_bank[] */
+	uint64_t checksum;		/* Checksum of memory_info data */
 };
 
-CASSERT(offsetof(struct ns_dram_info, num_banks) == 0UL,
+CASSERT(offsetof(struct memory_info, num_banks) == 0UL,
 			rmm_manifest_num_banks_unaligned);
-CASSERT(offsetof(struct ns_dram_info, banks) == 8UL,
+CASSERT(offsetof(struct memory_info, banks) == 8UL,
 			rmm_manifest_dram_data_unaligned);
-CASSERT(offsetof(struct ns_dram_info, checksum) == 16UL,
+CASSERT(offsetof(struct memory_info, checksum) == 16UL,
 			rmm_manifest_checksum_unaligned);
 
 /* Console info structure */
@@ -98,13 +98,18 @@
 CASSERT(offsetof(struct console_list, checksum) == 16UL,
 			rmm_manifest_console_list_checksum);
 
-/* Boot manifest core structure as per v0.3 */
+/* Boot manifest core structure as per v0.4 */
 struct rmm_manifest {
 	uint32_t version;			/* Manifest version */
 	uint32_t padding;			/* RES0 */
 	uintptr_t plat_data;			/* Manifest platform data */
-	struct ns_dram_info plat_dram;		/* Platform NS DRAM data (v0.2) */
-	struct console_list plat_console;	/* Platform console list (v0.3) */
+	/* Platform NS DRAM data (v0.2) */
+	struct memory_info plat_dram;
+	/* Platform console list (v0.3) */
+	struct console_list plat_console;
+	/* Platform device address ranges (v0.4) */
+	struct memory_info plat_ncoh_region;
+	struct memory_info plat_coh_region;
 };
 
 CASSERT(offsetof(struct rmm_manifest, version) == 0UL,
@@ -115,5 +120,9 @@
 			rmm_manifest_plat_dram_unaligned);
 CASSERT(offsetof(struct rmm_manifest, plat_console) == 40UL,
 			rmm_manifest_plat_console_unaligned);
+CASSERT(offsetof(struct rmm_manifest, plat_ncoh_region) == 64UL,
+			rmm_manifest_plat_ncoh_region_unaligned);
+CASSERT(offsetof(struct rmm_manifest, plat_coh_region) == 88UL,
+			rmm_manifest_plat_coh_region_unaligned);
 
 #endif /* RMM_CORE_MANIFEST_H */
diff --git a/lib/cpus/aarch32/aem_generic.S b/lib/cpus/aarch32/aem_generic.S
index f4dc0d1..a424575 100644
--- a/lib/cpus/aarch32/aem_generic.S
+++ b/lib/cpus/aarch32/aem_generic.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -40,8 +40,11 @@
 	b	dcsw_op_all
 endfunc aem_generic_cluster_pwr_dwn
 
+func aem_generic_reset_func
+	bx	lr
+endfunc aem_generic_reset_func
 
 /* cpu_ops for Base AEM FVP */
-declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \
+declare_cpu_ops aem_generic, BASE_AEM_MIDR, aem_generic_reset_func, \
 	aem_generic_core_pwr_dwn, \
 	aem_generic_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/a64fx.S b/lib/cpus/aarch64/a64fx.S
index 4893a44..a53467a 100644
--- a/lib/cpus/aarch64/a64fx.S
+++ b/lib/cpus/aarch64/a64fx.S
@@ -29,12 +29,15 @@
 a64fx_regs:  /* The ascii list of register names to be reported */
         .asciz  ""
 
+cpu_reset_func_start a64fx
+cpu_reset_func_end a64fx
+
 func a64fx_cpu_reg_dump
         adr     x6, a64fx_regs
         ret
 endfunc a64fx_cpu_reg_dump
 
-declare_cpu_ops a64fx, A64FX_MIDR, CPU_NO_RESET_FUNC \
+declare_cpu_ops a64fx, A64FX_MIDR, a64fx_reset_func \
                 a64fx_core_pwr_dwn, \
                 a64fx_cluster_pwr_dwn
 
diff --git a/lib/cpus/aarch64/aem_generic.S b/lib/cpus/aarch64/aem_generic.S
index d5634cf..9843943 100644
--- a/lib/cpus/aarch64/aem_generic.S
+++ b/lib/cpus/aarch64/aem_generic.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,8 @@
 #include <asm_macros.S>
 #include <cpu_macros.S>
 
+cpu_reset_prologue aem_generic
+
 func aem_generic_core_pwr_dwn
 	/* ---------------------------------------------
 	 * Disable the Data Cache.
@@ -74,6 +76,9 @@
 	b	dcsw_op_all
 endfunc aem_generic_cluster_pwr_dwn
 
+cpu_reset_func_start aem_generic
+cpu_reset_func_end aem_generic
+
 	/* ---------------------------------------------
 	 * This function provides cpu specific
 	 * register information for crash reporting.
@@ -94,11 +99,11 @@
 
 
 /* cpu_ops for Base AEM FVP */
-declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \
+declare_cpu_ops aem_generic, BASE_AEM_MIDR, aem_generic_reset_func, \
 	aem_generic_core_pwr_dwn, \
 	aem_generic_cluster_pwr_dwn
 
 /* cpu_ops for Foundation FVP */
-declare_cpu_ops aem_generic, FOUNDATION_AEM_MIDR, CPU_NO_RESET_FUNC, \
+declare_cpu_ops aem_generic, FOUNDATION_AEM_MIDR, aem_generic_reset_func, \
 	aem_generic_core_pwr_dwn, \
 	aem_generic_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a320.S b/lib/cpus/aarch64/cortex_a320.S
new file mode 100644
index 0000000..2d38b88
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a320.S
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a320.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A320 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-A320 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+cpu_reset_prologue cortex_a320
+
+cpu_reset_func_start cortex_a320
+	/* Disable speculative loads */
+	msr	SSBS, xzr
+	enable_mpmm
+cpu_reset_func_end cortex_a320
+
+	/* ----------------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ----------------------------------------------------
+	 */
+func cortex_a320_core_pwr_dwn
+	/* ---------------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------------
+	 */
+	sysreg_bit_set CORTEX_A320_CPUPWRCTLR_EL1, CORTEX_A320_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	isb
+	ret
+endfunc cortex_a320_core_pwr_dwn
+
+	/* ---------------------------------------------
+	 * This function provides Cortex-A320 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a320_regs, "aS"
+cortex_a320_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a320_cpu_reg_dump
+	adr	x6, cortex_a320_regs
+	mrs	x8, CORTEX_A320_CPUECTLR_EL1
+	ret
+endfunc cortex_a320_cpu_reg_dump
+
+declare_cpu_ops cortex_a320, CORTEX_A320_MIDR, \
+	cortex_a320_reset_func, \
+	cortex_a320_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a35.S b/lib/cpus/aarch64/cortex_a35.S
index c3d8c8d..40e6200 100644
--- a/lib/cpus/aarch64/cortex_a35.S
+++ b/lib/cpus/aarch64/cortex_a35.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,7 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+cpu_reset_prologue cortex_a35
 	/* ---------------------------------------------
 	 * Disable L1 data cache and unified L2 cache
 	 * ---------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a510.S b/lib/cpus/aarch64/cortex_a510.S
index b49d45a..81a227b 100644
--- a/lib/cpus/aarch64/cortex_a510.S
+++ b/lib/cpus/aarch64/cortex_a510.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <common/bl_common.h>
 #include <cortex_a510.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <plat_macros.S>
 
 /* Hardware handled coherency */
@@ -21,6 +22,8 @@
 #error "Cortex-A510 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_a510
+
 workaround_reset_start cortex_a510, ERRATUM(1922240), ERRATA_A510_1922240
 	/* Apply the workaround by setting IMP_CMPXACTLR_EL1[11:10] = 0b11. */
 	sysreg_bitfield_insert CORTEX_A510_CMPXACTLR_EL1, CORTEX_A510_CMPXACTLR_EL1_SNPPREFERUNIQUE_DISABLE, \
@@ -108,25 +111,11 @@
 
 check_erratum_ls cortex_a510, ERRATUM(2218950), CPU_REV(1, 0)
 
-	/* --------------------------------------------------
-	 * This workaround is not a typical errata fix. MPMM
-	 * is disabled here, but this conflicts with the BL31
-	 * MPMM support. So in addition to simply disabling
-	 * the feature, a flag is set in the MPMM library
-	 * indicating that it should not be enabled even if
-	 * ENABLE_MPMM=1.
-	 * --------------------------------------------------
-	 */
 workaround_reset_start cortex_a510, ERRATUM(2250311), ERRATA_A510_2250311
 	/* Disable MPMM */
 	mrs	x0, CPUMPMMCR_EL3
 	bfm	x0, xzr, #0, #0 /* bfc instruction does not work in GCC */
 	msr	CPUMPMMCR_EL3, x0
-
-#if ENABLE_MPMM && IMAGE_BL31
-	/* If ENABLE_MPMM is set, tell the runtime lib to skip enabling it. */
-	bl mpmm_errata_disable
-#endif
 workaround_reset_end cortex_a510, ERRATUM(2250311)
 
 check_erratum_ls cortex_a510, ERRATUM(2250311), CPU_REV(1, 0)
@@ -180,15 +169,14 @@
 
 check_erratum_ls cortex_a510, ERRATUM(2684597), CPU_REV(1, 2)
 
-/*
- * ERRATA_DSU_2313941 :
- * The errata is defined in dsu_helpers.S but applies to cortex_a510
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a510_2313941, check_errata_dsu_2313941
-.equ erratum_cortex_a510_2313941_wa, errata_dsu_2313941_wa
-add_erratum_entry cortex_a510, ERRATUM(2313941), ERRATA_DSU_2313941, APPLY_AT_RESET
+workaround_reset_start cortex_a510, ERRATUM(2313941), ERRATA_DSU_2313941
+	errata_dsu_2313941_wa_impl
+workaround_reset_end cortex_a510, ERRATUM(2313941)
+
+check_erratum_custom_start cortex_a510, ERRATUM(2313941)
+	check_errata_dsu_2313941_impl
+	ret
+check_erratum_custom_end cortex_a510, ERRATUM(2313941)
 
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
@@ -207,6 +195,15 @@
 cpu_reset_func_start cortex_a510
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	/* skip enabling MPMM if this erratum is present */
+#if ERRATA_A510_2250311
+	/* the cpu_rev_var is kept in x14 */
+	mov	x14, x0
+	bl	check_erratum_cortex_a510_2250311
+	cbz	x0, skip_mpmm
+#endif
+	enable_mpmm
+skip_mpmm:
 cpu_reset_func_end cortex_a510
 
 	/* ---------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a520.S b/lib/cpus/aarch64/cortex_a520.S
index 811c836..ac8019e 100644
--- a/lib/cpus/aarch64/cortex_a520.S
+++ b/lib/cpus/aarch64/cortex_a520.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,7 +11,6 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
-/* .global erratum_cortex_a520_2938996_wa */
 .global check_erratum_cortex_a520_2938996
 
 /* Hardware handled coherency */
@@ -24,6 +23,8 @@
 #error "Cortex A520 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_a520
+
 workaround_reset_start cortex_a520, ERRATUM(2630792), ERRATA_A520_2630792
 	sysreg_bit_set CORTEX_A520_CPUACTLR_EL1, BIT(38)
 workaround_reset_end cortex_a520, ERRATUM(2630792)
@@ -36,23 +37,9 @@
 
 check_erratum_ls cortex_a520, ERRATUM(2858100), CPU_REV(0, 1)
 
-workaround_runtime_start cortex_a520, ERRATUM(2938996), ERRATA_A520_2938996, CORTEX_A520_MIDR
-workaround_runtime_end cortex_a520, ERRATUM(2938996)
-
-check_erratum_custom_start cortex_a520, ERRATUM(2938996)
+add_erratum_entry cortex_a520, ERRATUM(2938996), ERRATA_A520_2938996
 
-       /* This erratum needs to be enabled for r0p0 and r0p1.
-        * Check if revision is less than or equal to r0p1.
-        */
-
-#if ERRATA_A520_2938996
-       mov     x1, #1
-       b       cpu_rev_var_ls
-#else
-       mov     x0, #ERRATA_MISSING
-#endif
-       ret
-check_erratum_custom_end cortex_a520, ERRATUM(2938996)
+check_erratum_ls cortex_a520, ERRATUM(2938996), CPU_REV(0, 1)
 
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
@@ -71,6 +58,7 @@
 cpu_reset_func_start cortex_a520
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_a520
 
 	/* ---------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
index 4a5b318..dbfff87 100644
--- a/lib/cpus/aarch64/cortex_a53.S
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,6 +12,8 @@
 #include <plat_macros.S>
 #include <lib/cpus/errata.h>
 
+cpu_reset_prologue cortex_a53
+
 	/* ---------------------------------------------
 	 * Disable L1 data cache and unified L2 cache
 	 * ---------------------------------------------
@@ -36,12 +38,12 @@
 /* Due to the nature of the errata it is applied unconditionally when chosen */
 check_erratum_ls cortex_a53, ERRATUM(819472), CPU_REV(0, 1)
 /* erratum workaround is interleaved with generic code */
-add_erratum_entry cortex_a53, ERRATUM(819472), ERRATUM_ALWAYS_CHOSEN, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a53, ERRATUM(819472), ERRATUM_ALWAYS_CHOSEN
 
 /* Due to the nature of the errata it is applied unconditionally when chosen */
 check_erratum_ls cortex_a53, ERRATUM(824069), CPU_REV(0, 2)
 /* erratum workaround is interleaved with generic code */
-add_erratum_entry cortex_a53, ERRATUM(824069), ERRATUM_ALWAYS_CHOSEN, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a53, ERRATUM(824069), ERRATUM_ALWAYS_CHOSEN
 
 workaround_reset_start cortex_a53, ERRATUM(826319), ERRATA_A53_826319
 	mrs	x1, CORTEX_A53_L2ACTLR_EL1
@@ -55,7 +57,7 @@
 /* Due to the nature of the errata it is applied unconditionally when chosen */
 check_erratum_ls cortex_a53, ERRATUM(827319), CPU_REV(0, 2)
 /* erratum workaround is interleaved with generic code */
-add_erratum_entry cortex_a53, ERRATUM(827319), ERRATUM_ALWAYS_CHOSEN, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a53, ERRATUM(827319), ERRATUM_ALWAYS_CHOSEN
 
 check_erratum_custom_start cortex_a53, ERRATUM(835769)
 	cmp	x0, CPU_REV(0, 4)
@@ -78,7 +80,7 @@
 check_erratum_custom_end cortex_a53, ERRATUM(835769)
 
 /* workaround at build time */
-add_erratum_entry cortex_a53, ERRATUM(835769), ERRATA_A53_835769, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a53, ERRATUM(835769), ERRATA_A53_835769
 
 	/*
 	 * Disable the cache non-temporal hint.
@@ -114,7 +116,7 @@
 check_erratum_custom_end cortex_a53, ERRATUM(843419)
 
 /* workaround at build time */
-add_erratum_entry cortex_a53, ERRATUM(843419), ERRATA_A53_843419, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a53, ERRATUM(843419), ERRATA_A53_843419
 
 	/*
 	 * Earlier revisions of the core are affected as well, but don't
@@ -131,7 +133,7 @@
 check_erratum_chosen cortex_a53, ERRATUM(1530924), ERRATA_A53_1530924
 
 /* erratum has no workaround in the cpu. Generic code must take care */
-add_erratum_entry cortex_a53, ERRATUM(1530924), ERRATA_A53_1530924, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a53, ERRATUM(1530924), ERRATA_A53_1530924
 
 cpu_reset_func_start cortex_a53
 	/* Enable the SMP bit. */
diff --git a/lib/cpus/aarch64/cortex_a55.S b/lib/cpus/aarch64/cortex_a55.S
index d5a74e9..cf91431 100644
--- a/lib/cpus/aarch64/cortex_a55.S
+++ b/lib/cpus/aarch64/cortex_a55.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <common/bl_common.h>
 #include <cortex_a55.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <plat_macros.S>
 
 /* Hardware handled coherency */
@@ -19,23 +20,25 @@
 	.globl cortex_a55_reset_func
 	.globl cortex_a55_core_pwr_dwn
 
-/* ERRATA_DSU_798953:
- * The errata is defined in dsu_helpers.S but applies to cortex_a55
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a55_798953, check_errata_dsu_798953
-.equ erratum_cortex_a55_798953_wa, errata_dsu_798953_wa
-add_erratum_entry cortex_a55, ERRATUM(798953), ERRATA_DSU_798953, APPLY_AT_RESET
+cpu_reset_prologue cortex_a55
 
-/* ERRATA_DSU_936184:
- * The errata is defined in dsu_helpers.S but applies to cortex_a55
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a55_936184, check_errata_dsu_936184
-.equ erratum_cortex_a55_936184_wa, errata_dsu_936184_wa
-add_erratum_entry cortex_a55, ERRATUM(936184), ERRATA_DSU_936184, APPLY_AT_RESET
+workaround_reset_start cortex_a55, ERRATUM(798953), ERRATA_DSU_798953
+	errata_dsu_798953_wa_impl
+workaround_reset_end cortex_a55, ERRATUM(798953)
+
+check_erratum_custom_start cortex_a55, ERRATUM(798953)
+	check_errata_dsu_798953_impl
+	ret
+check_erratum_custom_end cortex_a55, ERRATUM(798953)
+
+workaround_reset_start cortex_a55, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end cortex_a55, ERRATUM(936184)
+
+check_erratum_custom_start cortex_a55, ERRATUM(936184)
+	check_errata_dsu_936184_impl
+	ret
+check_erratum_custom_end cortex_a55, ERRATUM(936184)
 
 workaround_reset_start cortex_a55, ERRATUM(768277), ERRATA_A55_768277
 	sysreg_bit_set CORTEX_A55_CPUACTLR_EL1, CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE
@@ -50,8 +53,7 @@
 
 check_erratum_custom_start cortex_a55, ERRATUM(778703)
 	mov	x16, x30
-	mov	x1, #0x00
-	bl	cpu_rev_var_ls
+	cpu_rev_var_ls	CPU_REV(0, 0)
 	/*
 	 * Check that no private L2 cache is configured
 	 */
@@ -111,7 +113,7 @@
 check_erratum_chosen cortex_a55, ERRATUM(1530923), ERRATA_A55_1530923
 
 /* erratum has no workaround in the cpu. Generic code must take care */
-add_erratum_entry cortex_a55, ERRATUM(1530923), ERRATA_A55_1530923, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a55, ERRATUM(1530923), ERRATA_A55_1530923
 
 cpu_reset_func_start cortex_a55
 cpu_reset_func_end cortex_a55
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
index fecb56f..adacc5c 100644
--- a/lib/cpus/aarch64/cortex_a57.S
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -13,6 +13,8 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+cpu_reset_prologue cortex_a57
+
 	/* ---------------------------------------------
 	 * Disable L1 data cache and unified L2 cache
 	 * ---------------------------------------------
@@ -81,7 +83,7 @@
 
 /* erratum always worked around, but report it correctly */
 check_erratum_ls cortex_a57, ERRATUM(813419), CPU_REV(0, 0)
-add_erratum_entry cortex_a57, ERRATUM(813419), ERRATUM_ALWAYS_CHOSEN, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a57, ERRATUM(813419), ERRATUM_ALWAYS_CHOSEN
 
 workaround_reset_start cortex_a57, ERRATUM(813420), ERRATA_A57_813420
 	sysreg_bit_set CORTEX_A57_CPUACTLR_EL1, CORTEX_A57_CPUACTLR_EL1_DCC_AS_DCCI
@@ -95,7 +97,7 @@
 
 check_erratum_ls cortex_a57, ERRATUM(814670), CPU_REV(0, 0)
 
-workaround_runtime_start cortex_a57, ERRATUM(817169), ERRATA_A57_817169, CORTEX_A57_MIDR
+workaround_runtime_start cortex_a57, ERRATUM(817169), ERRATA_A57_817169
 	/* Invalidate any TLB address */
 	mov	x0, #0
 	tlbi	vae3, x0
@@ -150,7 +152,7 @@
 
 check_erratum_chosen cortex_a57, ERRATUM(1319537), ERRATA_A57_1319537
 /* erratum has no workaround in the cpu. Generic code must take care */
-add_erratum_entry cortex_a57, ERRATUM(1319537), ERRATA_A57_1319537, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a57, ERRATUM(1319537), ERRATA_A57_1319537
 
 workaround_reset_start cortex_a57, CVE(2017, 5715), WORKAROUND_CVE_2017_5715
 #if IMAGE_BL31
diff --git a/lib/cpus/aarch64/cortex_a65.S b/lib/cpus/aarch64/cortex_a65.S
index 3023ecb..3c32adb 100644
--- a/lib/cpus/aarch64/cortex_a65.S
+++ b/lib/cpus/aarch64/cortex_a65.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,6 +10,7 @@
 #include <common/debug.h>
 #include <cortex_a65.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <plat_macros.S>
 
 /* Hardware handled coherency */
@@ -22,20 +23,19 @@
 #error "Cortex-A65 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
-/* -------------------------------------------------
- * The CPU Ops reset function for Cortex-A65.
- * Shall clobber: x0-x19
- * -------------------------------------------------
- */
-func cortex_a65_reset_func
-	mov	x19, x30
+cpu_reset_prologue cortex_a65
 
-#if ERRATA_DSU_936184
-	bl	errata_dsu_936184_wa
-#endif
+workaround_reset_start cortex_a65, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end cortex_a65, ERRATUM(936184)
 
-	ret	x19
-endfunc cortex_a65_reset_func
+check_erratum_custom_start cortex_a65, ERRATUM(936184)
+	check_errata_dsu_936184_impl
+	ret
+check_erratum_custom_end cortex_a65, ERRATUM(936184)
+
+cpu_reset_func_start cortex_a65
+cpu_reset_func_end cortex_a65
 
 func cortex_a65_cpu_pwr_dwn
 	mrs	x0, CORTEX_A65_CPUPWRCTLR_EL1
@@ -45,7 +45,6 @@
 	ret
 endfunc cortex_a65_cpu_pwr_dwn
 
-
 .section .rodata.cortex_a65_regs, "aS"
 cortex_a65_regs:  /* The ascii list of register names to be reported */
 	.asciz	"cpuectlr_el1", ""
diff --git a/lib/cpus/aarch64/cortex_a65ae.S b/lib/cpus/aarch64/cortex_a65ae.S
index 1cbb06a..f1a63b0 100644
--- a/lib/cpus/aarch64/cortex_a65ae.S
+++ b/lib/cpus/aarch64/cortex_a65ae.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,7 @@
 #include <cortex_a65ae.h>
 #include <cpu_macros.S>
 #include <plat_macros.S>
+#include <dsu_macros.S>
 
 /* Hardware handled coherency */
 #if !HW_ASSISTED_COHERENCY
@@ -22,15 +23,16 @@
 #error "Cortex-A65AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
- /*
-  * ERRATA_DSU_936184 :
-  * The errata is defined in dsu_helpers.S but applies to cortex_a65ae
-  * as well. Henceforth creating symbolic names to the already existing errata
-  * workaround functions to get them registered under the Errata Framework.
-  */
-.equ check_erratum_cortex_a65ae_936184, check_errata_dsu_936184
-.equ erratum_cortex_a65ae_936184_wa, errata_dsu_936184_wa
-add_erratum_entry cortex_a65ae, ERRATUM(936184), ERRATA_DSU_936184, APPLY_AT_RESET
+cpu_reset_prologue cortex_a65ae
+
+workaround_reset_start cortex_a65ae, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end cortex_a65ae, ERRATUM(936184)
+
+check_erratum_custom_start cortex_a65ae, ERRATUM(936184)
+	check_errata_dsu_936184_impl
+	ret
+check_erratum_custom_end cortex_a65ae, ERRATUM(936184)
 
 cpu_reset_func_start cortex_a65ae
 cpu_reset_func_end cortex_a65ae
diff --git a/lib/cpus/aarch64/cortex_a710.S b/lib/cpus/aarch64/cortex_a710.S
index 71ed6db..e8f5a80 100644
--- a/lib/cpus/aarch64/cortex_a710.S
+++ b/lib/cpus/aarch64/cortex_a710.S
@@ -9,6 +9,7 @@
 #include <common/bl_common.h>
 #include <cortex_a710.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <plat_macros.S>
 #include "wa_cve_2022_23960_bhb_vector.S"
 
@@ -28,6 +29,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A710_BHB_LOOP_COUNT, cortex_a710
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_a710
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_a710, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_A710_CPUECTLR_EL1, BIT(46)
@@ -164,21 +167,23 @@
 
 check_erratum_ls cortex_a710, ERRATUM(2282622), CPU_REV(2, 1)
 
+.global erratum_cortex_a710_2291219_wa
 workaround_runtime_start cortex_a710, ERRATUM(2291219), ERRATA_A710_2291219
-	/* Set bit 36 in ACTLR2_EL1 */
-	sysreg_bit_set CORTEX_A710_CPUACTLR2_EL1, CORTEX_A710_CPUACTLR2_EL1_BIT_36
+	/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
+	 * the workaround. Second call clears it to undo it. */
+	sysreg_bit_toggle CORTEX_A710_CPUACTLR2_EL1, CORTEX_A710_CPUACTLR2_EL1_BIT_36
 workaround_runtime_end cortex_a710, ERRATUM(2291219), NO_ISB
 
 check_erratum_ls cortex_a710, ERRATUM(2291219), CPU_REV(2, 0)
 
-/*
- * ERRATA_DSU_2313941 is defined in dsu_helpers.S but applies to Cortex-A710 as
- * well. Create a symbollic link to existing errata workaround to get them
- * registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a710_2313941, check_errata_dsu_2313941
-.equ erratum_cortex_a710_2313941_wa, errata_dsu_2313941_wa
-add_erratum_entry cortex_a710, ERRATUM(2313941), ERRATA_DSU_2313941, APPLY_AT_RESET
+workaround_reset_start cortex_a710, ERRATUM(2313941), ERRATA_DSU_2313941
+	errata_dsu_2313941_wa_impl
+workaround_reset_end cortex_a710, ERRATUM(2313941)
+
+check_erratum_custom_start cortex_a710, ERRATUM(2313941)
+	check_errata_dsu_2313941_impl
+	ret
+check_erratum_custom_end cortex_a710, ERRATUM(2313941)
 
 workaround_reset_start cortex_a710, ERRATUM(2371105), ERRATA_A710_2371105
 	/* Set bit 40 in CPUACTLR2_EL1 */
@@ -220,7 +225,7 @@
 
 check_erratum_chosen cortex_a710, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-add_erratum_entry cortex_a710, ERRATUM(3701772), ERRATA_A710_3701772, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a710, ERRATUM(3701772), ERRATA_A710_3701772
 
 check_erratum_ls cortex_a710, ERRATUM(3701772), CPU_REV(2, 1)
 
@@ -245,6 +250,7 @@
 cpu_reset_func_start cortex_a710
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_a710
 
 	/* ---------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a715.S b/lib/cpus/aarch64/cortex_a715.S
index fbc73ed..d9c0df2 100644
--- a/lib/cpus/aarch64/cortex_a715.S
+++ b/lib/cpus/aarch64/cortex_a715.S
@@ -28,6 +28,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A715_BHB_LOOP_COUNT, cortex_a715
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_a715
+
 workaround_reset_start cortex_a715, ERRATUM(2331818), ERRATA_A715_2331818
         sysreg_bit_set CORTEX_A715_CPUACTLR2_EL1, BIT(20)
 workaround_reset_end cortex_a715, ERRATUM(2331818)
@@ -129,13 +131,14 @@
 
 check_erratum_chosen cortex_a715, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-add_erratum_entry cortex_a715, ERRATUM(3699560), ERRATA_A715_3699560, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a715, ERRATUM(3699560), ERRATA_A715_3699560
 
 check_erratum_ls cortex_a715, ERRATUM(3699560), CPU_REV(1, 3)
 
 cpu_reset_func_start cortex_a715
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_a715
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
index c300ea7..fee28ee 100644
--- a/lib/cpus/aarch64/cortex_a72.S
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A72_BHB_LOOP_COUNT, cortex_a72
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_a72
+
 	/* ---------------------------------------------
 	 * Disable L1 data cache and unified L2 cache
 	 * ---------------------------------------------
@@ -92,7 +94,7 @@
 /* Due to the nature of the errata it is applied unconditionally when chosen */
 check_erratum_chosen cortex_a72, ERRATUM(1319367), ERRATA_A72_1319367
 /* erratum workaround is interleaved with generic code */
-add_erratum_entry cortex_a72, ERRATUM(1319367), ERRATA_A72_1319367, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a72, ERRATUM(1319367), ERRATA_A72_1319367
 
 workaround_reset_start cortex_a72, CVE(2017, 5715), WORKAROUND_CVE_2017_5715
 #if IMAGE_BL31
diff --git a/lib/cpus/aarch64/cortex_a720.S b/lib/cpus/aarch64/cortex_a720.S
index ab2c12f..e639996 100644
--- a/lib/cpus/aarch64/cortex_a720.S
+++ b/lib/cpus/aarch64/cortex_a720.S
@@ -22,6 +22,8 @@
 #error "Cortex A720 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_a720
+
 .global check_erratum_cortex_a720_3699561
 
 #if WORKAROUND_CVE_2022_23960
@@ -74,13 +76,14 @@
 
 check_erratum_chosen cortex_a720, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-add_erratum_entry cortex_a720, ERRATUM(3699561), ERRATA_A720_3699561, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a720, ERRATUM(3699561), ERRATA_A720_3699561
 
 check_erratum_ls cortex_a720, ERRATUM(3699561), CPU_REV(0, 2)
 
 cpu_reset_func_start cortex_a720
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_a720
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a720_ae.S b/lib/cpus/aarch64/cortex_a720_ae.S
index 57a5030..1d51c44 100644
--- a/lib/cpus/aarch64/cortex_a720_ae.S
+++ b/lib/cpus/aarch64/cortex_a720_ae.S
@@ -21,15 +21,18 @@
 #error "Cortex-A720AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_a720_ae
+
 .global check_erratum_cortex_a720_ae_3699562
 
-add_erratum_entry cortex_a720_ae, ERRATUM(3699562), ERRATA_A720_AE_3699562, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a720_ae, ERRATUM(3699562), ERRATA_A720_AE_3699562
 
 check_erratum_ls cortex_a720_ae, ERRATUM(3699562), CPU_REV(0, 0)
 
 cpu_reset_func_start cortex_a720_ae
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_a720_ae
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a725.S b/lib/cpus/aarch64/cortex_a725.S
index c4d6034..682ca45 100644
--- a/lib/cpus/aarch64/cortex_a725.S
+++ b/lib/cpus/aarch64/cortex_a725.S
@@ -21,15 +21,18 @@
 #error "Cortex-A725 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_a725
+
 .global check_erratum_cortex_a725_3699564
 
-add_erratum_entry cortex_a725, ERRATUM(3699564), ERRATA_A725_3699564, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a725, ERRATUM(3699564), ERRATA_A725_3699564
 
 check_erratum_ls cortex_a725, ERRATUM(3699564), CPU_REV(0, 1)
 
 cpu_reset_func_start cortex_a725
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_a725
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
index 2130ceb..d1fc6d4 100644
--- a/lib/cpus/aarch64/cortex_a73.S
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,6 +10,8 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+cpu_reset_prologue cortex_a73
+
 	/* ---------------------------------------------
 	 * Disable L1 data cache
 	 * ---------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
index 152c81f..13599ca 100644
--- a/lib/cpus/aarch64/cortex_a75.S
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <cortex_a75.h>
 #include <cpuamu.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 
 .global check_erratum_cortex_a75_764081
 
@@ -17,6 +18,8 @@
 #error "Cortex-A75 must be compiled with HW_ASSISTED_COHERENCY enabled"
 #endif
 
+cpu_reset_prologue cortex_a75
+
 workaround_reset_start cortex_a75, ERRATUM(764081), ERRATA_A75_764081
 	sysreg_bit_set sctlr_el3, SCTLR_IESB_BIT
 workaround_reset_end cortex_a75, ERRATUM(764081)
@@ -29,23 +32,23 @@
 
 check_erratum_ls cortex_a75, ERRATUM(790748), CPU_REV(0, 0)
 
-/* ERRATA_DSU_798953 :
- * The errata is defined in dsu_helpers.S but applies to cortex_a75
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a75_798953, check_errata_dsu_798953
-.equ erratum_cortex_a75_798953_wa, errata_dsu_798953_wa
-add_erratum_entry cortex_a75, ERRATUM(798953), ERRATA_DSU_798953, APPLY_AT_RESET
+workaround_reset_start cortex_a75, ERRATUM(798953), ERRATA_DSU_798953
+	errata_dsu_798953_wa_impl
+workaround_reset_end cortex_a75, ERRATUM(798953)
 
-/* ERRATA_DSU_936184 :
- * The errata is defined in dsu_helpers.S but applies to cortex_a75
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a75_936184, check_errata_dsu_936184
-.equ erratum_cortex_a75_936184_wa, errata_dsu_936184_wa
-add_erratum_entry cortex_a75, ERRATUM(936184), ERRATA_DSU_936184, APPLY_AT_RESET
+check_erratum_custom_start cortex_a75, ERRATUM(798953)
+	check_errata_dsu_798953_impl
+	ret
+check_erratum_custom_end cortex_a75, ERRATUM(798953)
+
+workaround_reset_start cortex_a75, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end cortex_a75, ERRATUM(936184)
+
+check_erratum_custom_start cortex_a75, ERRATUM(936184)
+	check_errata_dsu_936184_impl
+	ret
+check_erratum_custom_end cortex_a75, ERRATUM(936184)
 
 workaround_reset_start cortex_a75, CVE(2017, 5715), WORKAROUND_CVE_2017_5715
 #if IMAGE_BL31
diff --git a/lib/cpus/aarch64/cortex_a76.S b/lib/cpus/aarch64/cortex_a76.S
index 017086a..822ef05 100644
--- a/lib/cpus/aarch64/cortex_a76.S
+++ b/lib/cpus/aarch64/cortex_a76.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <common/bl_common.h>
 #include <cortex_a76.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <plat_macros.S>
 #include <services/arm_arch_svc.h>
 #include "wa_cve_2022_23960_bhb.S"
@@ -29,6 +30,8 @@
 #define ESR_EL3_A64_SMC0	0x5e000000
 #define ESR_EL3_A32_SMC0	0x4e000000
 
+cpu_reset_prologue cortex_a76
+
 #if DYNAMIC_WORKAROUND_CVE_2018_3639
 	/*
 	 * This macro applies the mitigation for CVE-2018-3639.
@@ -344,11 +347,10 @@
 check_erratum_custom_start cortex_a76, ERRATUM(1286807)
 #if ERRATA_A76_1286807
 	mov x0, #ERRATA_APPLIES
-	ret
 #else
-	mov	x1, #0x30
-	b	cpu_rev_var_ls
+	cpu_rev_var_ls	CPU_REV(3, 0)
 #endif
+	ret
 check_erratum_custom_end cortex_a76, ERRATUM(1286807)
 
 workaround_reset_start cortex_a76, ERRATUM(1791580), ERRATA_A76_1791580
@@ -419,35 +421,34 @@
 check_erratum_custom_start cortex_a76, ERRATUM(1165522)
 #if ERRATA_A76_1165522
 	mov	x0, #ERRATA_APPLIES
-	ret
 #else
-	mov	x1, #0x30
-	b	cpu_rev_var_ls
+	cpu_rev_var_ls	CPU_REV(3, 0)
 #endif
+	ret
 check_erratum_custom_end cortex_a76, ERRATUM(1165522)
 
 check_erratum_chosen cortex_a76, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
 /* erratum has no workaround in the cpu. Generic code must take care */
-add_erratum_entry cortex_a76, CVE(2022, 23960), WORKAROUND_CVE_2022_23960, NO_APPLY_AT_RESET
+add_erratum_entry cortex_a76, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-/* ERRATA_DSU_798953 :
- * The errata is defined in dsu_helpers.S but applies to cortex_a76
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a76_798953, check_errata_dsu_798953
-.equ erratum_cortex_a76_798953_wa, errata_dsu_798953_wa
-add_erratum_entry cortex_a76, ERRATUM(798953), ERRATA_DSU_798953, APPLY_AT_RESET
+workaround_reset_start cortex_a76, ERRATUM(798953), ERRATA_DSU_798953
+	errata_dsu_798953_wa_impl
+workaround_reset_end cortex_a76, ERRATUM(798953)
 
-/* ERRATA_DSU_936184 :
- * The errata is defined in dsu_helpers.S but applies to cortex_a76
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_a76_936184, check_errata_dsu_936184
-.equ erratum_cortex_a76_936184_wa, errata_dsu_936184_wa
-add_erratum_entry cortex_a76, ERRATUM(936184), ERRATA_DSU_936184, APPLY_AT_RESET
+check_erratum_custom_start cortex_a76, ERRATUM(798953)
+	check_errata_dsu_798953_impl
+	ret
+check_erratum_custom_end cortex_a76, ERRATUM(798953)
+
+workaround_reset_start cortex_a76, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end cortex_a76, ERRATUM(936184)
+
+check_erratum_custom_start cortex_a76, ERRATUM(936184)
+	check_errata_dsu_936184_impl
+	ret
+check_erratum_custom_end cortex_a76, ERRATUM(936184)
 
 cpu_reset_func_start cortex_a76
 
diff --git a/lib/cpus/aarch64/cortex_a76ae.S b/lib/cpus/aarch64/cortex_a76ae.S
index 2fe3dbc..54af9a0 100644
--- a/lib/cpus/aarch64/cortex_a76ae.S
+++ b/lib/cpus/aarch64/cortex_a76ae.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,8 @@
 #error "Cortex-A76AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_a76ae
+
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A76AE_BHB_LOOP_COUNT, cortex_a76ae
 #endif /* WORKAROUND_CVE_2022_23960 */
diff --git a/lib/cpus/aarch64/cortex_a77.S b/lib/cpus/aarch64/cortex_a77.S
index 766bdc0..7fb964d 100644
--- a/lib/cpus/aarch64/cortex_a77.S
+++ b/lib/cpus/aarch64/cortex_a77.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,6 +17,8 @@
 #error "Cortex-A77 must be compiled with HW_ASSISTED_COHERENCY enabled"
 #endif
 
+cpu_reset_prologue cortex_a77
+
 /* 64-bit only core */
 #if CTX_INCLUDE_AARCH32_REGS == 1
 #error "Cortex-A77 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
@@ -36,8 +38,7 @@
 workaround_reset_start cortex_a77, ERRATUM(1508412), ERRATA_A77_1508412
 	/* move cpu revision in again and compare against r0p0 */
 	mov	x0, x7
-	mov	x1, #CPU_REV(0, 0)
-	bl	cpu_rev_var_ls
+	cpu_rev_var_ls	CPU_REV(0, 0)
 	cbz	x0, 1f
 
 	ldr	x0, =0x0
diff --git a/lib/cpus/aarch64/cortex_a78.S b/lib/cpus/aarch64/cortex_a78.S
index 9f2ffdf..a66214b 100644
--- a/lib/cpus/aarch64/cortex_a78.S
+++ b/lib/cpus/aarch64/cortex_a78.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -24,6 +24,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A78_BHB_LOOP_COUNT, cortex_a78
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_a78
+
 /* Disable hardware page aggregation.Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_a78, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_A78_CPUECTLR_EL1, BIT(46)
diff --git a/lib/cpus/aarch64/cortex_a78_ae.S b/lib/cpus/aarch64/cortex_a78_ae.S
index 7fa1f9b..c537967 100644
--- a/lib/cpus/aarch64/cortex_a78_ae.S
+++ b/lib/cpus/aarch64/cortex_a78_ae.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  * Copyright (c) 2021-2023, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -22,6 +22,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A78_AE_BHB_LOOP_COUNT, cortex_a78_ae
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_a78_ae
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_a78_ae, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_A78_AE_CPUECTLR_EL1, BIT(46)
diff --git a/lib/cpus/aarch64/cortex_a78c.S b/lib/cpus/aarch64/cortex_a78c.S
index 3f6944a..aba7d25 100644
--- a/lib/cpus/aarch64/cortex_a78c.S
+++ b/lib/cpus/aarch64/cortex_a78c.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_A78C_BHB_LOOP_COUNT, cortex_a78c
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_a78c
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_a78c, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_A78C_CPUECTLR_EL1, BIT(46)
diff --git a/lib/cpus/aarch64/cortex_alto.S b/lib/cpus/aarch64/cortex_alto.S
index c0815f9..69a630d 100644
--- a/lib/cpus/aarch64/cortex_alto.S
+++ b/lib/cpus/aarch64/cortex_alto.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,26 +21,19 @@
 #error "Alto supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+#if ERRATA_SME_POWER_DOWN == 0
+#error "Travis needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
+#endif
+
+cpu_reset_prologue cortex_alto
+
 cpu_reset_func_start cortex_alto
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_alto
 
 func cortex_alto_core_pwr_dwn
-#if ENABLE_SME_FOR_NS
-        /* ---------------------------------------------------
-         * Disable SME if enabled and supported
-         * ---------------------------------------------------
-         */
-	mrs     x0, ID_AA64PFR1_EL1
-	ubfx	x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
-		#ID_AA64PFR1_EL1_SME_WIDTH
-        cmp     x0, #SME_NOT_IMPLEMENTED
-	b.eq	1f
-	msr	CORTEX_ALTO_SVCRSM, xzr
-	msr	CORTEX_ALTO_SVCRZA, xzr
-1:
-#endif
 	/* ---------------------------------------------------
 	 * Enable CPU power down bit in power control register
 	 * ---------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_arcadia.S b/lib/cpus/aarch64/cortex_arcadia.S
deleted file mode 100644
index c97d87d..0000000
--- a/lib/cpus/aarch64/cortex_arcadia.S
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <asm_macros.S>
-#include <common/bl_common.h>
-#include <cortex_arcadia.h>
-#include <cpu_macros.S>
-#include <plat_macros.S>
-
-/* Hardware handled coherency */
-#if HW_ASSISTED_COHERENCY == 0
-#error "Cortex-ARCADIA must be compiled with HW_ASSISTED_COHERENCY enabled"
-#endif
-
-/* 64-bit only core */
-#if CTX_INCLUDE_AARCH32_REGS == 1
-#error "Cortex-ARCADIA supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
-#endif
-
-cpu_reset_func_start cortex_arcadia
-	/* Disable speculative loads */
-	msr	SSBS, xzr
-cpu_reset_func_end cortex_arcadia
-
-	/* ----------------------------------------------------
-	 * HW will do the cache maintenance while powering down
-	 * ----------------------------------------------------
-	 */
-func cortex_arcadia_core_pwr_dwn
-	/* ---------------------------------------------------
-	 * Enable CPU power down bit in power control register
-	 * ---------------------------------------------------
-	 */
-	sysreg_bit_set CORTEX_ARCADIA_CPUPWRCTLR_EL1, CORTEX_ARCADIA_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
-	isb
-	ret
-endfunc cortex_arcadia_core_pwr_dwn
-
-	/* ---------------------------------------------
-	 * This function provides Cortex-Arcadia specific
-	 * register information for crash reporting.
-	 * It needs to return with x6 pointing to
-	 * a list of register names in ascii and
-	 * x8 - x15 having values of registers to be
-	 * reported.
-	 * ---------------------------------------------
-	 */
-.section .rodata.cortex_arcadia_regs, "aS"
-cortex_arcadia_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
-
-func cortex_arcadia_cpu_reg_dump
-	adr	x6, cortex_arcadia_regs
-	mrs	x8, CORTEX_ARCADIA_CPUECTLR_EL1
-	ret
-endfunc cortex_arcadia_cpu_reg_dump
-
-declare_cpu_ops cortex_arcadia, CORTEX_ARCADIA_MIDR, \
-	cortex_arcadia_reset_func, \
-	cortex_arcadia_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_gelas.S b/lib/cpus/aarch64/cortex_gelas.S
index 891e9a6..4cdec32 100644
--- a/lib/cpus/aarch64/cortex_gelas.S
+++ b/lib/cpus/aarch64/cortex_gelas.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,12 +21,26 @@
 #error "Gelas supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+#if FEAT_PABANDON == 0
+#error "Gelas must be compiled with FEAT_PABANDON enabled"
+#endif
+
+#if ERRATA_SME_POWER_DOWN == 0
+#error "Gelas needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
+#endif
+
+cpu_reset_prologue cortex_gelas
+
 cpu_reset_func_start cortex_gelas
 	/* ----------------------------------------------------
 	 * Disable speculative loads
 	 * ----------------------------------------------------
 	 */
 	msr	SSBS, xzr
+	/* model bug: not cleared on reset */
+	sysreg_bit_clear 	CORTEX_GELAS_CPUPWRCTLR_EL1, \
+		CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	enable_mpmm
 cpu_reset_func_end cortex_gelas
 
 	/* ----------------------------------------------------
@@ -34,25 +48,12 @@
 	 * ----------------------------------------------------
 	 */
 func cortex_gelas_core_pwr_dwn
-#if ENABLE_SME_FOR_NS
-        /* ---------------------------------------------------
-         * Disable SME if enabled and supported
-         * ---------------------------------------------------
-         */
-	mrs     x0, ID_AA64PFR1_EL1
-	ubfx	x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
-		#ID_AA64PFR1_EL1_SME_WIDTH
-        cmp     x0, #SME_NOT_IMPLEMENTED
-	b.eq	1f
-	msr	CORTEX_GELAS_SVCRSM, xzr
-	msr	CORTEX_GELAS_SVCRZA, xzr
-1:
-#endif
 	/* ---------------------------------------------------
-	 * Enable CPU power down bit in power control register
+	 * Flip CPU power down bit in power control register.
+	 * It will be set on powerdown and cleared on wakeup
 	 * ---------------------------------------------------
 	 */
-	sysreg_bit_set 	CORTEX_GELAS_CPUPWRCTLR_EL1, \
+	sysreg_bit_toggle CORTEX_GELAS_CPUPWRCTLR_EL1, \
 		CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
 	isb
 	ret
diff --git a/lib/cpus/aarch64/cortex_x1.S b/lib/cpus/aarch64/cortex_x1.S
index 5bd020c..27d181a 100644
--- a/lib/cpus/aarch64/cortex_x1.S
+++ b/lib/cpus/aarch64/cortex_x1.S
@@ -23,6 +23,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_X1_BHB_LOOP_COUNT, cortex_x1
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_x1
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_x1, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_X1_CPUECTLR_EL1, BIT(46)
diff --git a/lib/cpus/aarch64/cortex_x2.S b/lib/cpus/aarch64/cortex_x2.S
index c18ce3c..b11c37d 100644
--- a/lib/cpus/aarch64/cortex_x2.S
+++ b/lib/cpus/aarch64/cortex_x2.S
@@ -9,6 +9,7 @@
 #include <common/bl_common.h>
 #include <cortex_x2.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <plat_macros.S>
 #include "wa_cve_2022_23960_bhb_vector.S"
 
@@ -24,7 +25,7 @@
 
 .global check_erratum_cortex_x2_3701772
 
-add_erratum_entry cortex_x2, ERRATUM(3701772), ERRATA_X2_3701772, NO_APPLY_AT_RESET
+add_erratum_entry cortex_x2, ERRATUM(3701772), ERRATA_X2_3701772
 
 check_erratum_ls cortex_x2, ERRATUM(3701772), CPU_REV(2, 1)
 
@@ -32,6 +33,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_X2_BHB_LOOP_COUNT, cortex_x2
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_x2
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_x2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_X2_CPUECTLR_EL1, BIT(46)
@@ -164,15 +167,14 @@
 
 check_erratum_chosen cortex_x2, CVE(2022, 23960), WORKAROUND_CVE_2022_23960
 
-/*
- * ERRATA_DSU_2313941 :
- * The errata is defined in dsu_helpers.S but applies to cortex_x2
- * as well. Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_cortex_x2_2313941, check_errata_dsu_2313941
-.equ erratum_cortex_x2_2313941_wa, errata_dsu_2313941_wa
-add_erratum_entry cortex_x2, ERRATUM(2313941), ERRATA_DSU_2313941, APPLY_AT_RESET
+workaround_reset_start cortex_x2, ERRATUM(2313941), ERRATA_DSU_2313941
+	errata_dsu_2313941_wa_impl
+workaround_reset_end cortex_x2, ERRATUM(2313941)
+
+check_erratum_custom_start cortex_x2, ERRATUM(2313941)
+	check_errata_dsu_2313941_impl
+	ret
+check_erratum_custom_end cortex_x2, ERRATUM(2313941)
 
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
@@ -193,6 +195,7 @@
 cpu_reset_func_start cortex_x2
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_x2
 
 	/* ---------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_x3.S b/lib/cpus/aarch64/cortex_x3.S
index 24dbf9d..3d52dae 100644
--- a/lib/cpus/aarch64/cortex_x3.S
+++ b/lib/cpus/aarch64/cortex_x3.S
@@ -24,7 +24,7 @@
 
 .global check_erratum_cortex_x3_3701769
 
-add_erratum_entry cortex_x3, ERRATUM(3701769), ERRATA_X3_3701769, NO_APPLY_AT_RESET
+add_erratum_entry cortex_x3, ERRATUM(3701769), ERRATA_X3_3701769
 
 check_erratum_ls cortex_x3, ERRATUM(3701769), CPU_REV(1, 2)
 
@@ -32,6 +32,8 @@
 	wa_cve_2022_23960_bhb_vector_table CORTEX_X3_BHB_LOOP_COUNT, cortex_x3
 #endif /* WORKAROUND_CVE_2022_23960 */
 
+cpu_reset_prologue cortex_x3
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_x3, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_X3_CPUECTLR_EL1, BIT(46)
@@ -52,14 +54,17 @@
 
 check_erratum_ls cortex_x3, ERRATUM(2266875), CPU_REV(1, 0)
 
-workaround_runtime_start cortex_x3, ERRATUM(2302506), ERRATA_X3_2302506
+workaround_reset_start cortex_x3, ERRATUM(2302506), ERRATA_X3_2302506
 	sysreg_bit_set	CORTEX_X3_CPUACTLR2_EL1, BIT(0)
-workaround_runtime_end cortex_x3, ERRATUM(2302506), NO_ISB
+workaround_reset_end cortex_x3, ERRATUM(2302506)
 
 check_erratum_ls cortex_x3, ERRATUM(2302506), CPU_REV(1, 1)
 
+.global erratum_cortex_x3_2313909_wa
 workaround_runtime_start cortex_x3, ERRATUM(2313909), ERRATA_X3_2313909
-	sysreg_bit_set	CORTEX_X3_CPUACTLR2_EL1, CORTEX_X3_CPUACTLR2_EL1_BIT_36
+	/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
+	 * the workaround. Second call clears it to undo it. */
+	sysreg_bit_toggle CORTEX_X3_CPUACTLR2_EL1, CORTEX_X3_CPUACTLR2_EL1_BIT_36
 workaround_runtime_end cortex_x3, ERRATUM(2313909), NO_ISB
 
 check_erratum_ls cortex_x3, ERRATUM(2313909), CPU_REV(1, 0)
@@ -81,9 +86,9 @@
 
 check_erratum_ls cortex_x3, ERRATUM(2615812), CPU_REV(1, 1)
 
-workaround_runtime_start cortex_x3, ERRATUM(2641945), ERRATA_X3_2641945
+workaround_reset_start cortex_x3, ERRATUM(2641945), ERRATA_X3_2641945
 	sysreg_bit_set	CORTEX_X3_CPUACTLR6_EL1, BIT(41)
-workaround_runtime_end cortex_x3, ERRATUM(2641945), NO_ISB
+workaround_reset_end cortex_x3, ERRATUM(2641945)
 
 check_erratum_ls cortex_x3, ERRATUM(2641945), CPU_REV(1, 0)
 
@@ -131,6 +136,7 @@
 cpu_reset_func_start cortex_x3
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_x3
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_x4.S b/lib/cpus/aarch64/cortex_x4.S
index fded73f..c067981 100644
--- a/lib/cpus/aarch64/cortex_x4.S
+++ b/lib/cpus/aarch64/cortex_x4.S
@@ -22,6 +22,8 @@
 #error "Cortex X4 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue cortex_x4
+
 .global check_erratum_cortex_x4_2726228
 .global check_erratum_cortex_x4_3701758
 
@@ -29,23 +31,9 @@
         wa_cve_2022_23960_bhb_vector_table CORTEX_X4_BHB_LOOP_COUNT, cortex_x4
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-workaround_runtime_start cortex_x4, ERRATUM(2726228), ERRATA_X4_2726228, CORTEX_X4_MIDR
-workaround_runtime_end cortex_x4, ERRATUM(2726228)
-
-check_erratum_custom_start cortex_x4, ERRATUM(2726228)
-
-	/* This erratum needs to be enabled for r0p0 and r0p1.
-	 * Check if revision is less than or equal to r0p1.
-	 */
+add_erratum_entry cortex_x4, ERRATUM(2726228), ERRATA_X4_2726228
 
-#if ERRATA_X4_2726228
-	mov	x1, #1
-	b	cpu_rev_var_ls
-#else
-	mov	x0, #ERRATA_MISSING
-#endif
-	ret
-check_erratum_custom_end cortex_x4, ERRATUM(2726228)
+check_erratum_ls cortex_x4, ERRATUM(2726228), CPU_REV(0, 1)
 
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_x4, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
@@ -89,6 +77,21 @@
 
 check_erratum_ls cortex_x4, ERRATUM(2923985), CPU_REV(0, 1)
 
+workaround_reset_start cortex_x4, ERRATUM(2957258), ERRATA_X4_2957258
+	/* Add ISB before MRS reads of MPIDR_EL1/MIDR_EL1 */
+	ldr x0, =0x1
+	msr S3_6_c15_c8_0, x0 	/* msr CPUPSELR_EL3, X0 */
+	ldr x0, =0xd5380000
+	msr S3_6_c15_c8_2, x0 	/* msr CPUPOR_EL3, X0 */
+	ldr x0, =0xFFFFFF40
+	msr S3_6_c15_c8_3,x0 	/* msr CPUPMR_EL3, X0 */
+	ldr x0, =0x000080010033f
+	msr S3_6_c15_c8_1, x0	/* msr CPUPCR_EL3, X0 */
+	isb
+workaround_reset_end cortex_x4, ERRATUM(2957258)
+
+check_erratum_ls cortex_x4, ERRATUM(2957258), CPU_REV(0, 1)
+
 workaround_reset_start cortex_x4, ERRATUM(3076789), ERRATA_X4_3076789
 	sysreg_bit_set CORTEX_X4_CPUACTLR3_EL1, BIT(14)
 	sysreg_bit_set CORTEX_X4_CPUACTLR3_EL1, BIT(13)
@@ -120,13 +123,14 @@
 
 check_erratum_chosen cortex_x4, CVE(2024, 7881), WORKAROUND_CVE_2024_7881
 
-add_erratum_entry cortex_x4, ERRATUM(3701758), ERRATA_X4_3701758, NO_APPLY_AT_RESET
+add_erratum_entry cortex_x4, ERRATUM(3701758), ERRATA_X4_3701758
 
 check_erratum_ls cortex_x4, ERRATUM(3701758), CPU_REV(0, 3)
 
 cpu_reset_func_start cortex_x4
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_x4
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cortex_x925.S b/lib/cpus/aarch64/cortex_x925.S
index e2e70dd..093d91d 100644
--- a/lib/cpus/aarch64/cortex_x925.S
+++ b/lib/cpus/aarch64/cortex_x925.S
@@ -21,12 +21,27 @@
 #error "Cortex-X925 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
-.global check_erratum_cortex_x925_3701747
+cpu_reset_prologue cortex_x925
 
-add_erratum_entry cortex_x925, ERRATUM(3701747), ERRATA_X925_3701747, NO_APPLY_AT_RESET
+add_erratum_entry cortex_x925, ERRATUM(3701747), ERRATA_X925_3701747
 
 check_erratum_ls cortex_x925, ERRATUM(3701747), CPU_REV(0, 1)
 
+workaround_reset_start cortex_x925, ERRATUM(2963999), ERRATA_X925_2963999
+	/* Add ISB before MRS reads of MPIDR_EL1/MIDR_EL1 */
+	ldr x0, =0x0
+	msr S3_6_c15_c8_0, x0 	/* msr CPUPSELR_EL3, X0 */
+	ldr x0, =0xd5380000
+	msr S3_6_c15_c8_2, x0 	/* msr CPUPOR_EL3, X0 */
+	ldr x0, =0xFFFFFF40
+	msr S3_6_c15_c8_3,x0 	/* msr CPUPMR_EL3, X0 */
+	ldr x0, =0x000080010033f
+	msr S3_6_c15_c8_1, x0	/* msr CPUPCR_EL3, X0 */
+	isb
+workaround_reset_end cortex_x925, ERRATUM(2963999)
+
+check_erratum_ls cortex_x925, ERRATUM(2963999), CPU_REV(0, 0)
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start cortex_x925, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set CORTEX_X925_CPUECTLR_EL1, BIT(46)
@@ -48,6 +63,7 @@
 cpu_reset_func_start cortex_x925
 	/* Disable speculative loads */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end cortex_x925
 
 	/* ----------------------------------------------------
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
index 0f9a3b8..e608422 100644
--- a/lib/cpus/aarch64/cpu_helpers.S
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,47 +14,6 @@
 #include <lib/cpus/errata.h>
 #include <lib/el3_runtime/cpu_data.h>
 
- /* Reset fn is needed in BL at reset vector */
-#if defined(IMAGE_BL1) || defined(IMAGE_BL31) ||	\
-	(defined(IMAGE_BL2) && RESET_TO_BL2)
-	/*
-	 * The reset handler common to all platforms.  After a matching
-	 * cpu_ops structure entry is found, the correponding reset_handler
-	 * in the cpu_ops is invoked.
-	 * Clobbers: x0 - x19, x30
-	 */
-	.globl	reset_handler
-func reset_handler
-	mov	x19, x30
-
-	/* The plat_reset_handler can clobber x0 - x18, x30 */
-	bl	plat_reset_handler
-
-	/* Get the matching cpu_ops pointer */
-	bl	get_cpu_ops_ptr
-
-#if ENABLE_ASSERTIONS
-	/*
-	 * Assert if invalid cpu_ops obtained. If this is not valid, it may
-	 * suggest that the proper CPU file hasn't been included.
-	 */
-	cmp	x0, #0
-	ASM_ASSERT(ne)
-#endif
-
-	/* Get the cpu_ops reset handler */
-	ldr	x2, [x0, #CPU_RESET_FUNC]
-	mov	x30, x19
-	cbz	x2, 1f
-
-	/* The cpu_ops reset handler can clobber x0 - x19, x30 */
-	br	x2
-1:
-	ret
-endfunc reset_handler
-
-#endif
-
 #ifdef IMAGE_BL31 /* The power down core and cluster is needed only in  BL31 */
 	/*
 	 * void prepare_cpu_pwr_dwn(unsigned int power_level)
@@ -213,83 +172,24 @@
 	b	1b
 error_exit:
 #endif
+#if ENABLE_ASSERTIONS
+	/*
+	 * Assert if invalid cpu_ops obtained. If this is not valid, it may
+	 * suggest that the proper CPU file hasn't been included.
+	 */
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
 	ret
 endfunc get_cpu_ops_ptr
 
-/*
- * Extract CPU revision and variant, and combine them into a single numeric for
- * easier comparison.
- */
 	.globl	cpu_get_rev_var
 func cpu_get_rev_var
-	mrs	x1, midr_el1
-
-	/*
-	 * Extract the variant[23:20] and revision[3:0] from MIDR, and pack them
-	 * as variant[7:4] and revision[3:0] of x0.
-	 *
-	 * First extract x1[23:16] to x0[7:0] and zero fill the rest. Then
-	 * extract x1[3:0] into x0[3:0] retaining other bits.
-	 */
-	ubfx	x0, x1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
-	bfxil	x0, x1, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+	get_rev_var x0, x1
 	ret
 endfunc cpu_get_rev_var
 
 /*
- * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
- * application purposes. If the revision-variant is less than or same as a given
- * value, indicates that errata applies; otherwise not.
- *
- * Shall clobber: x0-x3
- */
-	.globl	cpu_rev_var_ls
-func cpu_rev_var_ls
-	mov	x2, #ERRATA_APPLIES
-	mov	x3, #ERRATA_NOT_APPLIES
-	cmp	x0, x1
-	csel	x0, x2, x3, ls
-	ret
-endfunc cpu_rev_var_ls
-
-/*
- * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
- * application purposes. If the revision-variant is higher than or same as a
- * given value, indicates that errata applies; otherwise not.
- *
- * Shall clobber: x0-x3
- */
-	.globl	cpu_rev_var_hs
-func cpu_rev_var_hs
-	mov	x2, #ERRATA_APPLIES
-	mov	x3, #ERRATA_NOT_APPLIES
-	cmp	x0, x1
-	csel	x0, x2, x3, hs
-	ret
-endfunc cpu_rev_var_hs
-
-/*
- * Compare the CPU's revision-variant (x0) with a given range (x1 - x2), for errata
- * application purposes. If the revision-variant is between or includes the given
- * values, this indicates that errata applies; otherwise not.
- *
- * Shall clobber: x0-x4
- */
-	.globl	cpu_rev_var_range
-func cpu_rev_var_range
-	mov	x3, #ERRATA_APPLIES
-	mov	x4, #ERRATA_NOT_APPLIES
-	cmp	x0, x1
-	csel	x1, x3, x4, hs
-	cbz	x1, 1f
-	cmp	x0, x2
-	csel	x1, x3, x4, ls
-1:
-	mov	x0, x1
-	ret
-endfunc cpu_rev_var_range
-
-/*
  * int check_wa_cve_2017_5715(void);
  *
  * This function returns:
diff --git a/lib/cpus/aarch64/denver.S b/lib/cpus/aarch64/denver.S
index ca250d3..64158e7 100644
--- a/lib/cpus/aarch64/denver.S
+++ b/lib/cpus/aarch64/denver.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2020-2022, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -13,6 +13,8 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+cpu_reset_prologue denver
+
 	/* -------------------------------------------------
 	 * CVE-2017-5715 mitigation
 	 *
diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
deleted file mode 100644
index 3c5bf2e..0000000
--- a/lib/cpus/aarch64/dsu_helpers.S
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (c) 2019-2023, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <asm_macros.S>
-#include <dsu_def.h>
-#include <lib/cpus/errata.h>
-
-	/* -----------------------------------------------------------------------
-	 * DSU erratum 798953 check function
-	 * Checks the DSU variant, revision and configuration to determine if
-	 * the erratum applies. Erratum applies on all configurations of the
-	 * DSU and if revision-variant is r0p0.
-	 *
-	 * The erratum was fixed in r0p1.
-	 *
-	 * This function is called from both assembly and C environment. So it
-	 * follows AAPCS.
-	 *
-	 * Clobbers: x0-x3
-	 * -----------------------------------------------------------------------
-	 */
-	.globl	check_errata_dsu_798953
-	.globl	errata_dsu_798953_wa
-	.globl	dsu_pwr_dwn
-
-func check_errata_dsu_798953
-	mov	x2, #ERRATA_APPLIES
-	mov	x3, #ERRATA_NOT_APPLIES
-
-	/* Check if DSU is equal to r0p0 */
-	mrs	x1, CLUSTERIDR_EL1
-
-	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
-	ubfx	x0, x1, #CLUSTERIDR_REV_SHIFT,\
-			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
-	mov	x1, #(0x0 << CLUSTERIDR_REV_SHIFT)
-	cmp	x0, x1
-	csel	x0, x2, x3, EQ
-	ret
-endfunc check_errata_dsu_798953
-
-	/* --------------------------------------------------
-	 * Errata Workaround for DSU erratum #798953.
-	 *
-	 * Can clobber only: x0-x8
-	 * --------------------------------------------------
-	 */
-func errata_dsu_798953_wa
-	mov	x8, x30
-	bl	check_errata_dsu_798953
-	cbz	x0, 1f
-
-	/* If erratum applies, disable high-level clock gating */
-	mrs	x0, CLUSTERACTLR_EL1
-	orr	x0, x0, #CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING
-	msr	CLUSTERACTLR_EL1, x0
-	isb
-1:
-	ret	x8
-endfunc errata_dsu_798953_wa
-
-	/* -----------------------------------------------------------------------
-	 * DSU erratum 936184 check function
-	 * Checks the DSU variant, revision and configuration to determine if
-	 * the erratum applies. Erratum applies if ACP interface is present
-	 * in the DSU and revision-variant < r2p0.
-	 *
-	 * The erratum was fixed in r2p0.
-	 *
-	 * This function is called from both assembly and C environment. So it
-	 * follows AAPCS.
-	 *
-	 * Clobbers: x0-x4
-	 * -----------------------------------------------------------------------
-	 */
-	.globl	check_errata_dsu_936184
-	.globl	errata_dsu_936184_wa
-	.weak	is_scu_present_in_dsu
-
-	/* --------------------------------------------------------------------
-	 * Default behaviour respresents SCU is always present with DSU.
-	 * CPUs can override this definition if required.
-	 *
-	 * Can clobber only: x0-x3
-	 * --------------------------------------------------------------------
-	 */
-func is_scu_present_in_dsu
-	mov	x0, #1
-	ret
-endfunc is_scu_present_in_dsu
-
-func check_errata_dsu_936184
-	mov	x4, x30
-	bl	is_scu_present_in_dsu
-	cmp	x0, xzr
-	/* Default error status */
-	mov	x0, #ERRATA_NOT_APPLIES
-
-	/* If SCU is not present, return without applying patch */
-	b.eq	1f
-
-	/* Erratum applies only if DSU has the ACP interface */
-	mrs	x1, CLUSTERCFR_EL1
-	ubfx	x1, x1, #CLUSTERCFR_ACP_SHIFT, #1
-	cbz	x1, 1f
-
-	/* If ACP is present, check if DSU is older than r2p0 */
-	mrs	x1, CLUSTERIDR_EL1
-
-	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
-	ubfx	x2, x1, #CLUSTERIDR_REV_SHIFT,\
-			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
-	cmp x2, #(0x2 << CLUSTERIDR_VAR_SHIFT)
-	b.hs	1f
-	mov	x0, #ERRATA_APPLIES
-1:
-	ret	x4
-endfunc check_errata_dsu_936184
-
-	/* --------------------------------------------------
-	 * Errata Workaround for DSU erratum #936184.
-	 *
-	 * Can clobber only: x0-x8
-	 * --------------------------------------------------
-	 */
-func errata_dsu_936184_wa
-	mov	x8, x30
-	bl	check_errata_dsu_936184
-	cbz	x0, 1f
-
-	/* If erratum applies, we set a mask to a DSU control register */
-	mrs	x0, CLUSTERACTLR_EL1
-	ldr	x1, =DSU_ERRATA_936184_MASK
-	orr	x0, x0, x1
-	msr	CLUSTERACTLR_EL1, x0
-	isb
-1:
-	ret	x8
-endfunc errata_dsu_936184_wa
-
-	/* -----------------------------------------------------------------------
-	 * DSU erratum 2313941 check function
-	 * Checks the DSU variant, revision and configuration to determine if
-	 * the erratum applies. Erratum applies on all configurations of the
-	 * DSU and if revision-variant is r0p0, r1p0, r2p0, r2p1, r3p0, r3p1.
-	 *
-	 * The erratum is still open.
-	 *
-	 * This function is called from both assembly and C environment. So it
-	 * follows AAPCS.
-	 *
-	 * Clobbers: x0-x4
-	 * -----------------------------------------------------------------------
-	 */
-	.globl	check_errata_dsu_2313941
-	.globl	errata_dsu_2313941_wa
-
-func check_errata_dsu_2313941
-	mov	x4, x30
-	bl	is_scu_present_in_dsu
-	cmp	x0, xzr
-	/* Default error status */
-	mov	x0, #ERRATA_NOT_APPLIES
-
-	/* If SCU is not present, return without applying patch */
-	b.eq	1f
-
-	mov	x2, #ERRATA_APPLIES
-	mov	x3, #ERRATA_NOT_APPLIES
-
-	/* Check if DSU version is less than or equal to r3p1 */
-	mrs	x1, CLUSTERIDR_EL1
-
-	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
-	ubfx	x0, x1, #CLUSTERIDR_REV_SHIFT,\
-			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
-	mov	x1, #(0x31 << CLUSTERIDR_REV_SHIFT)
-	cmp	x0, x1
-	csel	x0, x2, x3, LS
-1:
-	ret	x4
-endfunc check_errata_dsu_2313941
-
-	/* --------------------------------------------------
-	 * Errata Workaround for DSU erratum #2313941.
-	 *
-	 * Can clobber only: x0-x8
-	 * --------------------------------------------------
-	 */
-func errata_dsu_2313941_wa
-	mov	x8, x30
-	bl	check_errata_dsu_2313941
-	cbz	x0, 1f
-
-	/* If erratum applies, disable high-level clock gating */
-	mrs	x0, CLUSTERACTLR_EL1
-	orr	x0, x0, #CLUSTERACTLR_EL1_DISABLE_SCLK_GATING
-	msr	CLUSTERACTLR_EL1, x0
-	isb
-1:
-	ret	x8
-endfunc errata_dsu_2313941_wa
-
-	/* ---------------------------------------------
-	 * controls power features of the cluster
-	 * 1. Cache portion power not request
-	 * 2. Disable the retention circuit
-	 * ---------------------------------------------
-	 */
-func dsu_pwr_dwn
-	msr	CLUSTERPWRCTLR_EL1, xzr
-	isb
-	ret
-endfunc dsu_pwr_dwn
diff --git a/lib/cpus/aarch64/generic.S b/lib/cpus/aarch64/generic.S
index 5d7a857..0a10eed 100644
--- a/lib/cpus/aarch64/generic.S
+++ b/lib/cpus/aarch64/generic.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,8 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+cpu_reset_prologue generic
+
 	/* ---------------------------------------------
 	 * Disable L1 data cache and unified L2 cache
 	 * ---------------------------------------------
@@ -80,7 +82,9 @@
  * ---------------------------------------------
  */
 .equ	generic_cpu_reg_dump,		0
-.equ	generic_reset_func,		0
+
+cpu_reset_func_start generic
+cpu_reset_func_end generic
 
 declare_cpu_ops generic, AARCH64_GENERIC_MIDR, \
 	generic_reset_func, \
diff --git a/lib/cpus/aarch64/neoverse_e1.S b/lib/cpus/aarch64/neoverse_e1.S
index 4bc95d0..f37bb28 100644
--- a/lib/cpus/aarch64/neoverse_e1.S
+++ b/lib/cpus/aarch64/neoverse_e1.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,7 @@
 #include <asm_macros.S>
 #include <common/bl_common.h>
 #include <common/debug.h>
+#include <dsu_macros.S>
 #include <neoverse_e1.h>
 #include <cpu_macros.S>
 #include <plat_macros.S>
@@ -21,15 +22,18 @@
 #error "Neoverse-E1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
-/*
- * ERRATA_DSU_936184:
- * The errata is defined in dsu_helpers.S and applies to neoverse_e1.
- * Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_neoverse_e1_936184, check_errata_dsu_936184
-.equ erratum_neoverse_e1_936184_wa, errata_dsu_936184_wa
-add_erratum_entry neoverse_e1, ERRATUM(936184), ERRATA_DSU_936184, APPLY_AT_RESET
+cpu_reset_prologue neoverse_e1
+
+workaround_reset_start neoverse_e1, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end neoverse_e1, ERRATUM(936184)
+
+check_erratum_custom_start neoverse_e1, ERRATUM(936184)
+	branch_if_scu_not_present 2f /* label 1 is used in the macro */
+	check_errata_dsu_936184_impl
+	2:
+	ret
+check_erratum_custom_end neoverse_e1, ERRATUM(936184)
 
 cpu_reset_func_start neoverse_e1
 cpu_reset_func_end neoverse_e1
diff --git a/lib/cpus/aarch64/neoverse_n1.S b/lib/cpus/aarch64/neoverse_n1.S
index f727226..1ad9557 100644
--- a/lib/cpus/aarch64/neoverse_n1.S
+++ b/lib/cpus/aarch64/neoverse_n1.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,7 @@
 #include <asm_macros.S>
 #include <cpuamu.h>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <neoverse_n1.h>
 #include "wa_cve_2022_23960_bhb_vector.S"
 
@@ -27,15 +28,18 @@
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_N1_BHB_LOOP_COUNT, neoverse_n1
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-/*
- * ERRATA_DSU_936184:
- * The errata is defined in dsu_helpers.S and applies to Neoverse N1.
- * Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_neoverse_n1_936184, check_errata_dsu_936184
-.equ erratum_neoverse_n1_936184_wa, errata_dsu_936184_wa
-add_erratum_entry neoverse_n1, ERRATUM(936184), ERRATA_DSU_936184, APPLY_AT_RESET
+cpu_reset_prologue neoverse_n1
+
+workaround_reset_start neoverse_n1, ERRATUM(936184), ERRATA_DSU_936184
+	errata_dsu_936184_wa_impl
+workaround_reset_end neoverse_n1, ERRATUM(936184)
+
+check_erratum_custom_start neoverse_n1, ERRATUM(936184)
+	branch_if_scu_not_present 2f /* label 1 is used in the macro */
+	check_errata_dsu_936184_impl
+	2:
+	ret
+check_erratum_custom_end neoverse_n1, ERRATUM(936184)
 
 workaround_reset_start neoverse_n1, ERRATUM(1043202), ERRATA_N1_1043202
 	/* Apply instruction patching sequence */
diff --git a/lib/cpus/aarch64/neoverse_n2.S b/lib/cpus/aarch64/neoverse_n2.S
index 3df3839..9c6f01a 100644
--- a/lib/cpus/aarch64/neoverse_n2.S
+++ b/lib/cpus/aarch64/neoverse_n2.S
@@ -7,6 +7,7 @@
 #include <arch.h>
 #include <asm_macros.S>
 #include <cpu_macros.S>
+#include <dsu_macros.S>
 #include <neoverse_n2.h>
 #include "wa_cve_2022_23960_bhb_vector.S"
 
@@ -22,7 +23,7 @@
 
 .global check_erratum_neoverse_n2_3701773
 
-add_erratum_entry neoverse_n2, ERRATUM(3701773), ERRATA_N2_3701773, NO_APPLY_AT_RESET
+add_erratum_entry neoverse_n2, ERRATUM(3701773), ERRATA_N2_3701773
 
 check_erratum_ls neoverse_n2, ERRATUM(3701773), CPU_REV(0, 3)
 
@@ -30,15 +31,18 @@
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_N2_BHB_LOOP_COUNT, neoverse_n2
 #endif /* WORKAROUND_CVE_2022_23960 */
 
-/*
- * ERRATA_DSU_2313941:
- * The errata is defined in dsu_helpers.S and applies to Neoverse N2.
- * Henceforth creating symbolic names to the already existing errata
- * workaround functions to get them registered under the Errata Framework.
- */
-.equ check_erratum_neoverse_n2_2313941, check_errata_dsu_2313941
-.equ erratum_neoverse_n2_2313941_wa, errata_dsu_2313941_wa
-add_erratum_entry neoverse_n2, ERRATUM(2313941), ERRATA_DSU_2313941, APPLY_AT_RESET
+cpu_reset_prologue neoverse_n2
+
+workaround_reset_start neoverse_n2, ERRATUM(2313941), ERRATA_DSU_2313941
+	errata_dsu_2313941_wa_impl
+workaround_reset_end neoverse_n2, ERRATUM(2313941)
+
+check_erratum_custom_start neoverse_n2, ERRATUM(2313941)
+	branch_if_scu_not_present 2f /* label 1 is used in the macro */
+	check_errata_dsu_2313941_impl
+	2:
+	ret
+check_erratum_custom_end neoverse_n2, ERRATUM(2313941)
 
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start neoverse_n2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
@@ -171,27 +175,29 @@
 
 check_erratum_ls neoverse_n2, ERRATUM(2280757), CPU_REV(0, 0)
 
+.global erratum_neoverse_n2_2326639_wa
 workaround_runtime_start neoverse_n2, ERRATUM(2326639), ERRATA_N2_2326639
-	/* Set bit 36 in ACTLR2_EL1 */
-	sysreg_bit_set NEOVERSE_N2_CPUACTLR2_EL1, NEOVERSE_N2_CPUACTLR2_EL1_BIT_36
+	/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
+	 * the workaround. Second call clears it to undo it. */
+	sysreg_bit_toggle NEOVERSE_N2_CPUACTLR2_EL1, NEOVERSE_N2_CPUACTLR2_EL1_BIT_36
 workaround_runtime_end neoverse_n2, ERRATUM(2326639)
 
 check_erratum_ls neoverse_n2, ERRATUM(2326639), CPU_REV(0, 0)
 
-workaround_runtime_start neoverse_n2, ERRATUM(2340933), ERRATA_N2_2340933
+workaround_reset_start neoverse_n2, ERRATUM(2340933), ERRATA_N2_2340933
 	/* Set bit 61 in CPUACTLR5_EL1 */
 	sysreg_bit_set NEOVERSE_N2_CPUACTLR5_EL1, BIT(61)
-workaround_runtime_end neoverse_n2, ERRATUM(2340933)
+workaround_reset_end neoverse_n2, ERRATUM(2340933)
 
 check_erratum_ls neoverse_n2, ERRATUM(2340933), CPU_REV(0, 0)
 
-workaround_runtime_start neoverse_n2, ERRATUM(2346952), ERRATA_N2_2346952
+workaround_reset_start neoverse_n2, ERRATUM(2346952), ERRATA_N2_2346952
 	/* Set TXREQ to STATIC and full L2 TQ size */
 	mrs	x1, NEOVERSE_N2_CPUECTLR2_EL1
 	mov	x0, #CPUECTLR2_EL1_TXREQ_STATIC_FULL
 	bfi	x1, x0, #CPUECTLR2_EL1_TXREQ_LSB, #CPUECTLR2_EL1_TXREQ_WIDTH
 	msr	NEOVERSE_N2_CPUECTLR2_EL1, x1
-workaround_runtime_end neoverse_n2, ERRATUM(2346952)
+workaround_reset_end neoverse_n2, ERRATUM(2346952)
 
 check_erratum_ls neoverse_n2, ERRATUM(2346952), CPU_REV(0, 2)
 
diff --git a/lib/cpus/aarch64/neoverse_n3.S b/lib/cpus/aarch64/neoverse_n3.S
index 8abcafe..1b7a3e1 100644
--- a/lib/cpus/aarch64/neoverse_n3.S
+++ b/lib/cpus/aarch64/neoverse_n3.S
@@ -21,9 +21,11 @@
 #error "Neoverse-N3 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue neoverse_n3
+
 .global check_erratum_neoverse_n3_3699563
 
-add_erratum_entry neoverse_n3, ERRATUM(3699563), ERRATA_N3_3699563, NO_APPLY_AT_RESET
+add_erratum_entry neoverse_n3, ERRATUM(3699563), ERRATA_N3_3699563
 
 check_erratum_ls neoverse_n3, ERRATUM(3699563), CPU_REV(0, 0)
 
diff --git a/lib/cpus/aarch64/neoverse_n_common.S b/lib/cpus/aarch64/neoverse_n_common.S
deleted file mode 100644
index b816342..0000000
--- a/lib/cpus/aarch64/neoverse_n_common.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <asm_macros.S>
-#include <neoverse_n_common.h>
-
-	.global is_scu_present_in_dsu
-
-/*
- * Check if the SCU L3 Unit is present on the DSU
- * 1-> SCU present
- * 0-> SCU not present
- *
- * This function is implemented as weak on dsu_helpers.S and must be
- * overwritten for Neoverse Nx cores.
- */
-
-func is_scu_present_in_dsu
-	mrs	x0, CPUCFR_EL1
-	ubfx	x0, x0, #SCU_SHIFT, #1
-	eor	x0, x0, #1
-	ret
-endfunc is_scu_present_in_dsu
diff --git a/lib/cpus/aarch64/neoverse_v1.S b/lib/cpus/aarch64/neoverse_v1.S
index d1a2c24..e1e8214 100644
--- a/lib/cpus/aarch64/neoverse_v1.S
+++ b/lib/cpus/aarch64/neoverse_v1.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,6 +22,8 @@
 #error "Neoverse-V1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue neoverse_v1
+
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_V1_BHB_LOOP_COUNT, neoverse_v1
 #endif /* WORKAROUND_CVE_2022_23960 */
@@ -203,10 +205,10 @@
 
 check_erratum_ls neoverse_v1, ERRATUM(2294912), CPU_REV(1, 2)
 
-workaround_runtime_start neoverse_v1, ERRATUM(2348377), ERRATA_V1_2348377
+workaround_reset_start neoverse_v1, ERRATUM(2348377), ERRATA_V1_2348377
 	/* Set bit 61 in CPUACTLR5_EL1 */
 	sysreg_bit_set NEOVERSE_V1_ACTLR5_EL1, NEOVERSE_V1_ACTLR5_EL1_BIT_61
-workaround_runtime_end neoverse_v1, ERRATUM(2348377)
+workaround_reset_end neoverse_v1, ERRATUM(2348377)
 
 check_erratum_ls neoverse_v1, ERRATUM(2348377), CPU_REV(1, 1)
 
diff --git a/lib/cpus/aarch64/neoverse_v2.S b/lib/cpus/aarch64/neoverse_v2.S
index b43f6dd..06521ec 100644
--- a/lib/cpus/aarch64/neoverse_v2.S
+++ b/lib/cpus/aarch64/neoverse_v2.S
@@ -22,6 +22,8 @@
 #error "Neoverse V2 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue neoverse_v2
+
 /* Disable hardware page aggregation. Enables mitigation for `CVE-2024-5660` */
 workaround_reset_start neoverse_v2, CVE(2024, 5660), WORKAROUND_CVE_2024_5660
 	sysreg_bit_set NEOVERSE_V2_CPUECTLR_EL1, BIT(46)
diff --git a/lib/cpus/aarch64/neoverse_v3.S b/lib/cpus/aarch64/neoverse_v3.S
index 7fe2d7f..29bfd0e 100644
--- a/lib/cpus/aarch64/neoverse_v3.S
+++ b/lib/cpus/aarch64/neoverse_v3.S
@@ -22,12 +22,29 @@
 #error "Neoverse V3 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue neoverse_v3
+
 .global check_erratum_neoverse_v3_3701767
 
-add_erratum_entry neoverse_v3, ERRATUM(3701767), ERRATA_V3_3701767, NO_APPLY_AT_RESET
+add_erratum_entry neoverse_v3, ERRATUM(3701767), ERRATA_V3_3701767
 
 check_erratum_ls neoverse_v3, ERRATUM(3701767), CPU_REV(0, 2)
 
+workaround_reset_start neoverse_v3, ERRATUM(2970647), ERRATA_V3_2970647
+	/* Add ISB before MRS reads of MPIDR_EL1/MIDR_EL1 */
+	ldr x0, =0x1
+	msr S3_6_c15_c8_0, x0 	/* msr CPUPSELR_EL3, X0 */
+	ldr x0, =0xd5380000
+	msr S3_6_c15_c8_2, x0 	/* msr CPUPOR_EL3, X0 */
+	ldr x0, =0xFFFFFF40
+	msr S3_6_c15_c8_3,x0 	/* msr CPUPMR_EL3, X0 */
+	ldr x0, =0x000080010033f
+	msr S3_6_c15_c8_1, x0	/* msr CPUPCR_EL3, X0 */
+	isb
+workaround_reset_end neoverse_v3, ERRATUM(2970647)
+
+check_erratum_ls neoverse_v3, ERRATUM(2970647), CPU_REV(0, 0)
+
 #if WORKAROUND_CVE_2022_23960
 	wa_cve_2022_23960_bhb_vector_table NEOVERSE_V3_BHB_LOOP_COUNT, neoverse_v3
 #endif /* WORKAROUND_CVE_2022_23960 */
diff --git a/lib/cpus/aarch64/nevis.S b/lib/cpus/aarch64/nevis.S
index 0180ab7..b2aa26e 100644
--- a/lib/cpus/aarch64/nevis.S
+++ b/lib/cpus/aarch64/nevis.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,12 +21,15 @@
 #error "Nevis supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue nevis
+
 cpu_reset_func_start nevis
 	/* ----------------------------------------------------
 	 * Disable speculative loads
 	 * ----------------------------------------------------
 	 */
 	msr	SSBS, xzr
+	enable_mpmm
 cpu_reset_func_end nevis
 
 func nevis_core_pwr_dwn
diff --git a/lib/cpus/aarch64/qemu_max.S b/lib/cpus/aarch64/qemu_max.S
index fb03cf1..a727379 100644
--- a/lib/cpus/aarch64/qemu_max.S
+++ b/lib/cpus/aarch64/qemu_max.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,8 @@
 #include <cpu_macros.S>
 #include <qemu_max.h>
 
+cpu_reset_prologue qemu_max
+
 func qemu_max_core_pwr_dwn
 	/* ---------------------------------------------
 	 * Disable the Data Cache.
@@ -47,6 +49,9 @@
 	b	dcsw_op_all
 endfunc qemu_max_cluster_pwr_dwn
 
+cpu_reset_func_start qemu_max
+cpu_reset_func_end qemu_max
+
 	/* ---------------------------------------------
 	 * This function provides cpu specific
 	 * register information for crash reporting.
@@ -67,6 +72,6 @@
 
 
 /* cpu_ops for QEMU MAX */
-declare_cpu_ops qemu_max, QEMU_MAX_MIDR, CPU_NO_RESET_FUNC, \
+declare_cpu_ops qemu_max, QEMU_MAX_MIDR, qemu_max_reset_func, \
 	qemu_max_core_pwr_dwn, \
 	qemu_max_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/rainier.S b/lib/cpus/aarch64/rainier.S
index ea687be..9ad9362 100644
--- a/lib/cpus/aarch64/rainier.S
+++ b/lib/cpus/aarch64/rainier.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,8 @@
 #error "Rainier CPU supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+cpu_reset_prologue rainier
+
 /* --------------------------------------------------
  * Disable speculative loads if Rainier supports
  * SSBS.
diff --git a/lib/cpus/aarch64/travis.S b/lib/cpus/aarch64/travis.S
index e8b3860..d53e46f 100644
--- a/lib/cpus/aarch64/travis.S
+++ b/lib/cpus/aarch64/travis.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,34 +21,35 @@
 #error "Travis supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+#if FEAT_PABANDON == 0
+#error "Travis must be compiled with FEAT_PABANDON enabled"
+#endif
+
+#if ERRATA_SME_POWER_DOWN == 0
+#error "Travis needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
+#endif
+
+cpu_reset_prologue travis
+
 cpu_reset_func_start travis
 	/* ----------------------------------------------------
 	 * Disable speculative loads
 	 * ----------------------------------------------------
 	 */
 	msr	SSBS, xzr
+	/* model bug: not cleared on reset */
+	sysreg_bit_clear TRAVIS_IMP_CPUPWRCTLR_EL1, \
+		TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
+	enable_mpmm
 cpu_reset_func_end travis
 
 func travis_core_pwr_dwn
-#if ENABLE_SME_FOR_NS
-        /* ---------------------------------------------------
-         * Disable SME if enabled and supported
-         * ---------------------------------------------------
-         */
-	mrs     x0, ID_AA64PFR1_EL1
-	ubfx	x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
-		#ID_AA64PFR1_EL1_SME_WIDTH
-        cmp     x0, #SME_NOT_IMPLEMENTED
-	b.eq	1f
-	msr	TRAVIS_SVCRSM, xzr
-	msr	TRAVIS_SVCRZA, xzr
-1:
-#endif
 	/* ---------------------------------------------------
-	 * Enable CPU power down bit in power control register
+	 * Flip CPU power down bit in power control register.
+	 * It will be set on powerdown and cleared on wakeup
 	 * ---------------------------------------------------
 	 */
-	sysreg_bit_set TRAVIS_IMP_CPUPWRCTLR_EL1, \
+	sysreg_bit_toggle TRAVIS_IMP_CPUPWRCTLR_EL1, \
 		TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
 	isb
 	ret
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 0db7e94..8136624 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -564,6 +564,10 @@
 # still open.
 CPU_FLAG_LIST += ERRATA_V1_2779461
 
+# Flag to apply erratum 2970647 workaround during reset. This erratum applies
+# to revisions r0p0 of the Neoverse V3 cpu and is fixed in r0p1.
+CPU_FLAG_LIST += ERRATA_V3_2970647
+
 # Flag to apply erratum 3701767 workaround during context save/restore of
 # ICH_VMCR_EL2 reg. This erratum applies to revisions r0p0, r0p1 and r0p2 of
 # the Neoverse V3 cpu and is still open.
@@ -885,6 +889,12 @@
 # to revisions r0p0 and r0p1 of the Cortex-X4 cpu. It is fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_X4_2923985
 
+# Flag to apply erratum 2957258 workaround to avoid incorrect virtualization of
+# MPIDR_EL1/VMPIDR_EL2 and MIDR_EL1/VPIDR_EL2 when reading in EL2/EL3. This
+# erratum applies to revisions r0p0, r0p1 of the Cortex-X4 cpu. It is fixed
+# in r0p2.
+CPU_FLAG_LIST += ERRATA_X4_2957258
+
 # Flag to apply erratum 3076789 workaround on reset. This erratum applies
 # to revisions r0p0 and r0p1 of the Cortex-X4 cpu. It is fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_X4_3076789
@@ -894,6 +904,10 @@
 # of the Cortex-X4 cpu and is still open.
 CPU_FLAG_LIST += ERRATA_X4_3701758
 
+# Flag to apply erratum 2963999 workaround during reset. This erratum applies
+# to revisions r0p0 of the Cortex-X925 cpu and is fixed in r0p1.
+CPU_FLAG_LIST += ERRATA_X925_2963999
+
 # Flag to apply erratum 3701747 workaround during context save/restore of
 # ICH_VMCR_EL2 reg. This erratum applies to revisions r0p0, r0p1 of the
 # Cortex-X925 cpu and is still open.
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index fed24f0..1e6a42e 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -75,6 +75,9 @@
  */
 #if CTX_INCLUDE_FPREGS
 func fpregs_context_save
+	/* Save x0 and pass its original value to fpregs_state_save */
+	mov	x1, x0
+
 	stp	q0, q1, [x0], #32
 	stp	q2, q3, [x0], #32
 	stp	q4, q5, [x0], #32
@@ -92,7 +95,7 @@
 	stp	q28, q29, [x0], #32
 	stp	q30, q31, [x0], #32
 
-	fpregs_state_save x0, x9
+	fpregs_state_save x1, x9
 
 	ret
 endfunc fpregs_context_save
@@ -112,6 +115,9 @@
  * ------------------------------------------------------------------
  */
 func fpregs_context_restore
+	/* Save x0 and pass its original value to fpregs_state_restore */
+	mov	x1, x0
+
 	ldp	q0, q1, [x0], #32
 	ldp	q2, q3, [x0], #32
 	ldp	q4, q5, [x0], #32
@@ -129,7 +135,7 @@
 	ldp	q28, q29, [x0], #32
 	ldp	q30, q31, [x0], #32
 
-	fpregs_state_restore x0, x9
+	fpregs_state_restore x1, x9
 
 	ret
 endfunc fpregs_context_restore
@@ -203,19 +209,6 @@
  */
 func sve_context_save
 .arch_extension sve
-	/* Temporarily enable SVE */
-	mrs	x10, cptr_el3
-	orr	x11, x10, #CPTR_EZ_BIT
-	bic	x11, x11, #TFP_BIT
-	msr	cptr_el3, x11
-	isb
-
-	/* zcr_el3 */
-	mrs	x12, S3_6_C1_C2_0
-	mov	x13, #((SVE_VECTOR_LEN >> 7) - 1)
-	msr	S3_6_C1_C2_0, x13
-	isb
-
 	/* Predicate registers */
 	mov x13, #CTX_SIMD_PREDICATES
 	add	x9, x0, x13
@@ -231,11 +224,6 @@
 	mov x13, #CTX_SIMD_VECTORS
 	add	x9, x0, x13
 	sve_vectors_op  str, x9
-
-	/* Restore SVE enablement */
-	msr	S3_6_C1_C2_0, x12 /* zcr_el3 */
-	msr	cptr_el3, x10
-	isb
 .arch_extension nosve
 
 	/* Save FPSR, FPCR and FPEXC32 */
@@ -254,19 +242,6 @@
  */
 func sve_context_restore
 .arch_extension sve
-	/* Temporarily enable SVE for EL3 */
-	mrs	x10, cptr_el3
-	orr	x11, x10, #CPTR_EZ_BIT
-	bic	x11, x11, #TFP_BIT
-	msr	cptr_el3, x11
-	isb
-
-	/* zcr_el3 */
-	mrs	x12, S3_6_C1_C2_0
-	mov	x13, #((SVE_VECTOR_LEN >> 7) - 1)
-	msr	S3_6_C1_C2_0, x13
-	isb
-
 	/* Restore FFR register before predicates */
 	mov x13, #CTX_SIMD_FFR
 	add	x9, x0, x13
@@ -282,11 +257,6 @@
 	mov x13, #CTX_SIMD_VECTORS
 	add	x9, x0, x13
 	sve_vectors_op	ldr, x9
-
-	/* Restore SVE enablement */
-	msr	S3_6_C1_C2_0, x12 /* zcr_el3 */
-	msr	cptr_el3, x10
-	isb
 .arch_extension nosve
 
 	/* Restore FPSR, FPCR and FPEXC32 */
@@ -598,10 +568,7 @@
 
 	/* ----------------------------------------------------------
 	 * Restore CPTR_EL3.
-	 * ZCR is only restored if SVE is supported and enabled.
-	 * Synchronization is required before zcr_el3 is addressed.
-	 * ----------------------------------------------------------
-	 */
+	 * ---------------------------------------------------------- */
 
 	/* The address of the per_world context is stored in x9 */
 	get_per_world_context x9
@@ -610,13 +577,6 @@
 	msr	cptr_el3, x19
 
 #if IMAGE_BL31
-	ands	x19, x19, #CPTR_EZ_BIT
-	beq	sve_not_enabled
-
-	isb
-	msr	S3_6_C1_C2_0, x20 /* zcr_el3 */
-sve_not_enabled:
-
 	restore_mpam3_el3
 
 #endif /* IMAGE_BL31 */
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index f396752..e28e1c3 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -191,6 +191,19 @@
 	}
 
 	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+
+	if (is_feat_fgt2_supported()) {
+		fgt2_enable(ctx);
+	}
+
+	if (is_feat_debugv8p9_supported()) {
+		debugv8p9_extended_bp_wp_enable(ctx);
+	}
+
+	if (is_feat_brbe_supported()) {
+		brbe_enable(ctx);
+	}
+
 }
 #endif /* ENABLE_RME */
 
@@ -648,13 +661,17 @@
 /*******************************************************************************
  * Enable architecture extensions for EL3 execution. This function only updates
  * registers in-place which are expected to either never change or be
- * overwritten by el3_exit.
+ * overwritten by el3_exit. Expects the core_pos of the current core as argument.
  ******************************************************************************/
 #if IMAGE_BL31
-void cm_manage_extensions_el3(void)
+void cm_manage_extensions_el3(unsigned int my_idx)
 {
+	if (is_feat_sve_supported()) {
+		sve_init_el3();
+	}
+
 	if (is_feat_amu_supported()) {
-		amu_init_el3();
+		amu_init_el3(my_idx);
 	}
 
 	if (is_feat_sme_supported()) {
@@ -790,6 +807,7 @@
 static void manage_extensions_nonsecure(cpu_context_t *ctx)
 {
 #if IMAGE_BL31
+	/* NOTE: registers are not context switched */
 	if (is_feat_amu_supported()) {
 		amu_enable(ctx);
 	}
@@ -1511,6 +1529,10 @@
 		write_el2_ctx_sxpoe(el2_sysregs_ctx, por_el2, read_por_el2());
 	}
 
+	if (is_feat_brbe_supported()) {
+		write_el2_ctx_brbe(el2_sysregs_ctx, brbcr_el2, read_brbcr_el2());
+	}
+
 	if (is_feat_s2pie_supported()) {
 		write_el2_ctx_s2pie(el2_sysregs_ctx, s2pir_el2, read_s2pir_el2());
 	}
@@ -1614,6 +1636,10 @@
 	if (is_feat_sctlr2_supported()) {
 		write_sctlr2_el2(read_el2_ctx_sctlr2(el2_sysregs_ctx, sctlr2_el2));
 	}
+
+	if (is_feat_brbe_supported()) {
+		write_brbcr_el2(read_el2_ctx_brbe(el2_sysregs_ctx, brbcr_el2));
+	}
 }
 #endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 
diff --git a/lib/el3_runtime/aarch64/cpu_data.S b/lib/el3_runtime/aarch64/cpu_data.S
index 313f882..02d9415 100644
--- a/lib/el3_runtime/aarch64/cpu_data.S
+++ b/lib/el3_runtime/aarch64/cpu_data.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,29 +7,9 @@
 #include <asm_macros.S>
 #include <lib/el3_runtime/cpu_data.h>
 
-.globl	init_cpu_data_ptr
 .globl	_cpu_data_by_index
 
 /* -----------------------------------------------------------------
- * void init_cpu_data_ptr(void)
- *
- * Initialise the TPIDR_EL3 register to refer to the cpu_data_t
- * for the calling CPU. This must be called before cm_get_cpu_data()
- *
- * This can be called without a valid stack. It assumes that
- * plat_my_core_pos() does not clobber register x10.
- * clobbers: x0, x1, x10
- * -----------------------------------------------------------------
- */
-func init_cpu_data_ptr
-	mov	x10, x30
-	bl	plat_my_core_pos
-	bl	_cpu_data_by_index
-	msr	tpidr_el3, x0
-	ret	x10
-endfunc init_cpu_data_ptr
-
-/* -----------------------------------------------------------------
  * cpu_data_t *_cpu_data_by_index(uint32_t cpu_index)
  *
  * Return the cpu_data structure for the CPU with given linear index
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
index 351a552..6faef87 100644
--- a/lib/extensions/amu/aarch32/amu.c
+++ b/lib/extensions/amu/aarch32/amu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,7 +8,6 @@
 #include <cdefs.h>
 #include <stdbool.h>
 
-#include "../amu_private.h"
 #include <arch.h>
 #include <arch_features.h>
 #include <arch_helpers.h>
@@ -18,51 +17,7 @@
 
 #include <plat/common/platform.h>
 
-struct amu_ctx {
-	uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS];
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint64_t group1_cnts[AMU_GROUP1_MAX_COUNTERS];
-#endif
-
-	uint16_t group0_enable;
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint16_t group1_enable;
-#endif
-};
-
-static struct amu_ctx amu_ctxs_[PLATFORM_CORE_COUNT];
-
-CASSERT((sizeof(amu_ctxs_[0].group0_enable) * CHAR_BIT) <= AMU_GROUP0_MAX_COUNTERS,
-	amu_ctx_group0_enable_cannot_represent_all_group0_counters);
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-CASSERT((sizeof(amu_ctxs_[0].group1_enable) * CHAR_BIT) <= AMU_GROUP1_MAX_COUNTERS,
-	amu_ctx_group1_enable_cannot_represent_all_group1_counters);
-#endif
-
-static inline __unused void write_hcptr_tam(uint32_t value)
-{
-	write_hcptr((read_hcptr() & ~TAM_BIT) |
-		((value << TAM_SHIFT) & TAM_BIT));
-}
-
-static inline __unused void write_amcr_cg1rz(uint32_t value)
-{
-	write_amcr((read_amcr() & ~AMCR_CG1RZ_BIT) |
-		((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
-}
-
-static inline __unused uint32_t read_amcfgr_ncg(void)
-{
-	return (read_amcfgr() >> AMCFGR_NCG_SHIFT) &
-		AMCFGR_NCG_MASK;
-}
-
-static inline __unused uint32_t read_amcgcr_cg0nc(void)
-{
-	return (read_amcgcr() >> AMCGCR_CG0NC_SHIFT) &
-		AMCGCR_CG0NC_MASK;
-}
+amu_regs_t amu_ctx[PLATFORM_CORE_COUNT];
 
 static inline __unused uint32_t read_amcgcr_cg1nc(void)
 {
@@ -70,134 +25,31 @@
 		AMCGCR_CG1NC_MASK;
 }
 
-static inline __unused uint32_t read_amcntenset0_px(void)
-{
-	return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) &
-		AMCNTENSET0_Pn_MASK;
-}
-
-static inline __unused uint32_t read_amcntenset1_px(void)
-{
-	return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) &
-		AMCNTENSET1_Pn_MASK;
-}
-
-static inline __unused void write_amcntenset0_px(uint32_t px)
-{
-	uint32_t value = read_amcntenset0();
-
-	value &= ~AMCNTENSET0_Pn_MASK;
-	value |= (px << AMCNTENSET0_Pn_SHIFT) &
-		AMCNTENSET0_Pn_MASK;
-
-	write_amcntenset0(value);
-}
-
-static inline __unused void write_amcntenset1_px(uint32_t px)
-{
-	uint32_t value = read_amcntenset1();
-
-	value &= ~AMCNTENSET1_Pn_MASK;
-	value |= (px << AMCNTENSET1_Pn_SHIFT) &
-		AMCNTENSET1_Pn_MASK;
-
-	write_amcntenset1(value);
-}
-
-static inline __unused void write_amcntenclr0_px(uint32_t px)
-{
-	uint32_t value = read_amcntenclr0();
-
-	value &= ~AMCNTENCLR0_Pn_MASK;
-	value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK;
-
-	write_amcntenclr0(value);
-}
-
-static inline __unused void write_amcntenclr1_px(uint32_t px)
-{
-	uint32_t value = read_amcntenclr1();
-
-	value &= ~AMCNTENCLR1_Pn_MASK;
-	value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK;
-
-	write_amcntenclr1(value);
-}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-static __unused bool amu_group1_supported(void)
-{
-	return read_amcfgr_ncg() > 0U;
-}
-#endif
-
 /*
  * Enable counters. This function is meant to be invoked by the context
  * management library before exiting from EL3.
  */
 void amu_enable(bool el2_unused)
 {
-	uint32_t amcfgr_ncg;		/* Number of counter groups */
-	uint32_t amcgcr_cg0nc;		/* Number of group 0 counters */
-
-	uint32_t amcntenset0_px = 0x0;	/* Group 0 enable mask */
-	uint32_t amcntenset1_px = 0x0;	/* Group 1 enable mask */
-
 	if (el2_unused) {
 		/*
 		 * HCPTR.TAM: Set to zero so any accesses to the Activity
 		 * Monitor registers do not trap to EL2.
 		 */
-		write_hcptr_tam(0U);
+		write_hcptr(read_hcptr() & ~TAM_BIT);
 	}
 
-	/*
-	 * Retrieve the number of architected counters. All of these counters
-	 * are enabled by default.
-	 */
-
-	amcgcr_cg0nc = read_amcgcr_cg0nc();
-	amcntenset0_px = (UINT32_C(1) << (amcgcr_cg0nc)) - 1U;
-
-	assert(amcgcr_cg0nc <= AMU_AMCGCR_CG0NC_MAX);
-
-	/*
-	 * The platform may opt to enable specific auxiliary counters. This can
-	 * be done via the common FCONF getter, or via the platform-implemented
-	 * function.
-	 */
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	const struct amu_topology *topology;
-
-#if ENABLE_AMU_FCONF
-	topology = FCONF_GET_PROPERTY(amu, config, topology);
-#else
-	topology = plat_amu_topology();
-#endif /* ENABLE_AMU_FCONF */
+	/* Architecture is currently pinned to 4 */
+	assert((read_amcgcr() & AMCGCR_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
 
-	if (topology != NULL) {
+	/* Enable all architected counters by default */
+	write_amcntenset0(AMCNTENSET0_Pn_MASK);
+	if (is_feat_amu_aux_supported()) {
 		unsigned int core_pos = plat_my_core_pos();
 
-		amcntenset1_el0_px = topology->cores[core_pos].enable;
-	} else {
-		ERROR("AMU: failed to generate AMU topology\n");
-	}
-#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
-
-	/*
-	 * Enable the requested counters.
-	 */
-
-	write_amcntenset0_px(amcntenset0_px);
-
-	amcfgr_ncg = read_amcfgr_ncg();
-	if (amcfgr_ncg > 0U) {
-		write_amcntenset1_px(amcntenset1_px);
-
-#if !ENABLE_AMU_AUXILIARY_COUNTERS
-		VERBOSE("AMU: auxiliary counters detected but support is disabled\n");
-#endif
+		/* Something went wrong if we're trying to write higher bits */
+		assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_Pn_MASK) == 0);
+		write_amcntenset1(get_amu_aux_enables(core_pos));
 	}
 
 	/* Bail out if FEAT_AMUv1p1 features are not present. */
@@ -214,180 +66,177 @@
 	 * mapped view are unaffected.
 	 */
 	VERBOSE("AMU group 1 counter access restricted.\n");
-	write_amcr_cg1rz(1U);
+	write_amcr(read_amcr() | 1U);
 #else
-	write_amcr_cg1rz(0U);
+	write_amcr(0);
 #endif
 }
 
-/* Read the group 0 counter identified by the given `idx`. */
-static uint64_t amu_group0_cnt_read(unsigned int idx)
-{
-	assert(is_feat_amu_supported());
-	assert(idx < read_amcgcr_cg0nc());
-
-	return amu_group0_cnt_read_internal(idx);
-}
-
-/* Write the group 0 counter identified by the given `idx` with `val` */
-static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
-{
-	assert(is_feat_amu_supported());
-	assert(idx < read_amcgcr_cg0nc());
-
-	amu_group0_cnt_write_internal(idx, val);
-	isb();
-}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-/* Read the group 1 counter identified by the given `idx` */
-static uint64_t amu_group1_cnt_read(unsigned  int idx)
-{
-	assert(is_feat_amu_supported());
-	assert(amu_group1_supported());
-	assert(idx < read_amcgcr_cg1nc());
-
-	return amu_group1_cnt_read_internal(idx);
-}
-
-/* Write the group 1 counter identified by the given `idx` with `val` */
-static void amu_group1_cnt_write(unsigned  int idx, uint64_t val)
-{
-	assert(is_feat_amu_supported());
-	assert(amu_group1_supported());
-	assert(idx < read_amcgcr_cg1nc());
-
-	amu_group1_cnt_write_internal(idx, val);
-	isb();
-}
-#endif
-
 static void *amu_context_save(const void *arg)
 {
-	uint32_t i;
-
-	unsigned int core_pos;
-	struct amu_ctx *ctx;
-
-	uint32_t amcgcr_cg0nc;	/* Number of group 0 counters */
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint32_t amcfgr_ncg;	/* Number of counter groups */
-	uint32_t amcgcr_cg1nc;	/* Number of group 1 counters */
-#endif
-
 	if (!is_feat_amu_supported()) {
 		return (void *)0;
 	}
 
-	core_pos = plat_my_core_pos();
-	ctx = &amu_ctxs_[core_pos];
-
-	amcgcr_cg0nc = read_amcgcr_cg0nc();
+	unsigned int core_pos = *(unsigned int *)arg;
+	amu_regs_t *ctx = &amu_ctx[core_pos];
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	amcfgr_ncg = read_amcfgr_ncg();
-	amcgcr_cg1nc = (amcfgr_ncg > 0U) ? read_amcgcr_cg1nc() : 0U;
-#endif
-
-	/*
-	 * Disable all AMU counters.
-	 */
-
-	ctx->group0_enable = read_amcntenset0_px();
-	write_amcntenclr0_px(ctx->group0_enable);
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	if (amcfgr_ncg > 0U) {
-		ctx->group1_enable = read_amcntenset1_px();
-		write_amcntenclr1_px(ctx->group1_enable);
+	/* Disable all counters so we can write to them safely later */
+	write_amcntenclr0(AMCNTENCLR0_Pn_MASK);
+	if (is_feat_amu_aux_supported()) {
+		write_amcntenclr1(get_amu_aux_enables(core_pos));
 	}
-#endif
-
-	/*
-	 * Save the counters to the local context.
-	 */
 
 	isb(); /* Ensure counters have been stopped */
 
-	for (i = 0U; i < amcgcr_cg0nc; i++) {
-		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
-	}
+	write_amu_grp0_ctx_reg(ctx, 0, read64_amevcntr00());
+	write_amu_grp0_ctx_reg(ctx, 1, read64_amevcntr01());
+	write_amu_grp0_ctx_reg(ctx, 2, read64_amevcntr02());
+	write_amu_grp0_ctx_reg(ctx, 3, read64_amevcntr03());
+
+	if (is_feat_amu_aux_supported()) {
+		uint8_t num_counters = read_amcgcr_cg1nc();
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	for (i = 0U; i < amcgcr_cg1nc; i++) {
-		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
+		switch (num_counters) {
+		case 0x10:
+			write_amu_grp1_ctx_reg(ctx, 0xf, read64_amevcntr1f());
+			__fallthrough;
+		case 0x0f:
+			write_amu_grp1_ctx_reg(ctx, 0xe, read64_amevcntr1e());
+			__fallthrough;
+		case 0x0e:
+			write_amu_grp1_ctx_reg(ctx, 0xd, read64_amevcntr1d());
+			__fallthrough;
+		case 0x0d:
+			write_amu_grp1_ctx_reg(ctx, 0xc, read64_amevcntr1c());
+			__fallthrough;
+		case 0x0c:
+			write_amu_grp1_ctx_reg(ctx, 0xb, read64_amevcntr1b());
+			__fallthrough;
+		case 0x0b:
+			write_amu_grp1_ctx_reg(ctx, 0xa, read64_amevcntr1a());
+			__fallthrough;
+		case 0x0a:
+			write_amu_grp1_ctx_reg(ctx, 0x9, read64_amevcntr19());
+			__fallthrough;
+		case 0x09:
+			write_amu_grp1_ctx_reg(ctx, 0x8, read64_amevcntr18());
+			__fallthrough;
+		case 0x08:
+			write_amu_grp1_ctx_reg(ctx, 0x7, read64_amevcntr17());
+			__fallthrough;
+		case 0x07:
+			write_amu_grp1_ctx_reg(ctx, 0x6, read64_amevcntr16());
+			__fallthrough;
+		case 0x06:
+			write_amu_grp1_ctx_reg(ctx, 0x5, read64_amevcntr15());
+			__fallthrough;
+		case 0x05:
+			write_amu_grp1_ctx_reg(ctx, 0x4, read64_amevcntr14());
+			__fallthrough;
+		case 0x04:
+			write_amu_grp1_ctx_reg(ctx, 0x3, read64_amevcntr13());
+			__fallthrough;
+		case 0x03:
+			write_amu_grp1_ctx_reg(ctx, 0x2, read64_amevcntr12());
+			__fallthrough;
+		case 0x02:
+			write_amu_grp1_ctx_reg(ctx, 0x1, read64_amevcntr11());
+			__fallthrough;
+		case 0x01:
+			write_amu_grp1_ctx_reg(ctx, 0x0, read64_amevcntr10());
+			__fallthrough;
+		case 0x00:
+			break;
+		default:
+			assert(0); /* something is wrong */
+		}
 	}
-#endif
 
 	return (void *)0;
 }
 
 static void *amu_context_restore(const void *arg)
 {
-	uint32_t i;
-
-	unsigned int core_pos;
-	struct amu_ctx *ctx;
-
-	uint32_t amcfgr_ncg;	/* Number of counter groups */
-	uint32_t amcgcr_cg0nc;	/* Number of group 0 counters */
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint32_t amcgcr_cg1nc;	/* Number of group 1 counters */
-#endif
-
 	if (!is_feat_amu_supported()) {
 		return (void *)0;
 	}
 
-	core_pos = plat_my_core_pos();
-	ctx = &amu_ctxs_[core_pos];
-
-	amcfgr_ncg = read_amcfgr_ncg();
-	amcgcr_cg0nc = read_amcgcr_cg0nc();
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	amcgcr_cg1nc = (amcfgr_ncg > 0U) ? read_amcgcr_cg1nc() : 0U;
-#endif
-
-	/*
-	 * Sanity check that all counters were disabled when the context was
-	 * previously saved.
-	 */
+	unsigned int core_pos = *(unsigned int *)arg;
+	amu_regs_t *ctx = &amu_ctx[core_pos];
 
-	assert(read_amcntenset0_px() == 0U);
-
-	if (amcfgr_ncg > 0U) {
-		assert(read_amcntenset1_px() == 0U);
-	}
-
-	/*
-	 * Restore the counter values from the local context.
-	 */
+	write64_amevcntr00(read_amu_grp0_ctx_reg(ctx, 0));
+	write64_amevcntr01(read_amu_grp0_ctx_reg(ctx, 1));
+	write64_amevcntr02(read_amu_grp0_ctx_reg(ctx, 2));
+	write64_amevcntr03(read_amu_grp0_ctx_reg(ctx, 3));
 
-	for (i = 0U; i < amcgcr_cg0nc; i++) {
-		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
-	}
+	if (is_feat_amu_aux_supported()) {
+		uint8_t num_counters = read_amcgcr_cg1nc();
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	for (i = 0U; i < amcgcr_cg1nc; i++) {
-		amu_group1_cnt_write(i, ctx->group1_cnts[i]);
+		switch (num_counters) {
+		case 0x10:
+			write64_amevcntr1f(read_amu_grp1_ctx_reg(ctx, 0xf));
+			__fallthrough;
+		case 0x0f:
+			write64_amevcntr1e(read_amu_grp1_ctx_reg(ctx, 0xe));
+			__fallthrough;
+		case 0x0e:
+			write64_amevcntr1d(read_amu_grp1_ctx_reg(ctx, 0xd));
+			__fallthrough;
+		case 0x0d:
+			write64_amevcntr1c(read_amu_grp1_ctx_reg(ctx, 0xc));
+			__fallthrough;
+		case 0x0c:
+			write64_amevcntr1b(read_amu_grp1_ctx_reg(ctx, 0xb));
+			__fallthrough;
+		case 0x0b:
+			write64_amevcntr1a(read_amu_grp1_ctx_reg(ctx, 0xa));
+			__fallthrough;
+		case 0x0a:
+			write64_amevcntr19(read_amu_grp1_ctx_reg(ctx, 0x9));
+			__fallthrough;
+		case 0x09:
+			write64_amevcntr18(read_amu_grp1_ctx_reg(ctx, 0x8));
+			__fallthrough;
+		case 0x08:
+			write64_amevcntr17(read_amu_grp1_ctx_reg(ctx, 0x7));
+			__fallthrough;
+		case 0x07:
+			write64_amevcntr16(read_amu_grp1_ctx_reg(ctx, 0x6));
+			__fallthrough;
+		case 0x06:
+			write64_amevcntr15(read_amu_grp1_ctx_reg(ctx, 0x5));
+			__fallthrough;
+		case 0x05:
+			write64_amevcntr14(read_amu_grp1_ctx_reg(ctx, 0x4));
+			__fallthrough;
+		case 0x04:
+			write64_amevcntr13(read_amu_grp1_ctx_reg(ctx, 0x3));
+			__fallthrough;
+		case 0x03:
+			write64_amevcntr12(read_amu_grp1_ctx_reg(ctx, 0x2));
+			__fallthrough;
+		case 0x02:
+			write64_amevcntr11(read_amu_grp1_ctx_reg(ctx, 0x1));
+			__fallthrough;
+		case 0x01:
+			write64_amevcntr10(read_amu_grp1_ctx_reg(ctx, 0x0));
+			__fallthrough;
+		case 0x00:
+			break;
+		default:
+			assert(0); /* something is wrong */
+		}
 	}
-#endif
-
-	/*
-	 * Re-enable counters that were disabled during context save.
-	 */
 
-	write_amcntenset0_px(ctx->group0_enable);
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	if (amcfgr_ncg > 0U) {
-		write_amcntenset1_px(ctx->group1_enable);
+	/* now enable them again */
+	write_amcntenset0(AMCNTENSET0_Pn_MASK);
+	if (is_feat_amu_aux_supported()) {
+		write_amcntenset1(get_amu_aux_enables(core_pos));
 	}
-#endif
 
+	isb();
 	return (void *)0;
 }
 
diff --git a/lib/extensions/amu/aarch32/amu_helpers.S b/lib/extensions/amu/aarch32/amu_helpers.S
deleted file mode 100644
index 7090b2d..0000000
--- a/lib/extensions/amu/aarch32/amu_helpers.S
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <assert_macros.S>
-#include <asm_macros.S>
-
-	.globl	amu_group0_cnt_read_internal
-	.globl	amu_group0_cnt_write_internal
-	.globl	amu_group1_cnt_read_internal
-	.globl	amu_group1_cnt_write_internal
-	.globl	amu_group1_set_evtype_internal
-
-/*
- * uint64_t amu_group0_cnt_read_internal(int idx);
- *
- * Given `idx`, read the corresponding AMU counter
- * and return it in `r0` and `r1`.
- */
-func amu_group0_cnt_read_internal
-#if ENABLE_ASSERTIONS
-	/* `idx` should be between [0, 3] */
-	mov	r1, r0
-	lsr	r1, r1, #2
-	cmp	r1, #0
-	ASM_ASSERT(eq)
-#endif
-
-	/*
-	 * Given `idx` calculate address of ldcopr16/bx lr instruction pair
-	 * in the table below.
-	 */
-	adr	r1, 1f
-	lsl	r0, r0, #3	/* each ldcopr16/bx lr sequence is 8 bytes */
-	add	r1, r1, r0
-	bx	r1
-1:
-	ldcopr16	r0, r1, AMEVCNTR00	/* index 0 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR01	/* index 1 */
-	bx 		lr
-	ldcopr16	r0, r1, AMEVCNTR02	/* index 2 */
-	bx 		lr
-	ldcopr16	r0, r1, AMEVCNTR03	/* index 3 */
-	bx 		lr
-endfunc amu_group0_cnt_read_internal
-
-/*
- * void amu_group0_cnt_write_internal(int idx, uint64_t val);
- *
- * Given `idx`, write `val` to the corresponding AMU counter.
- * `idx` is passed in `r0` and `val` is passed in `r2` and `r3`.
- * `r1` is used as a scratch register.
- */
-func amu_group0_cnt_write_internal
-#if ENABLE_ASSERTIONS
-	/* `idx` should be between [0, 3] */
-	mov	r1, r0
-	lsr	r1, r1, #2
-	cmp	r1, #0
-	ASM_ASSERT(eq)
-#endif
-
-	/*
-	 * Given `idx` calculate address of stcopr16/bx lr instruction pair
-	 * in the table below.
-	 */
-	adr	r1, 1f
-	lsl	r0, r0, #3	/* each stcopr16/bx lr sequence is 8 bytes */
-	add	r1, r1, r0
-	bx	r1
-
-1:
-	stcopr16	r2, r3, AMEVCNTR00	/* index 0 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR01	/* index 1 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR02	/* index 2 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR03	/* index 3 */
-	bx		lr
-endfunc amu_group0_cnt_write_internal
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-/*
- * uint64_t amu_group1_cnt_read_internal(int idx);
- *
- * Given `idx`, read the corresponding AMU counter
- * and return it in `r0` and `r1`.
- */
-func amu_group1_cnt_read_internal
-#if ENABLE_ASSERTIONS
-	/* `idx` should be between [0, 15] */
-	mov	r1, r0
-	lsr	r1, r1, #4
-	cmp	r1, #0
-	ASM_ASSERT(eq)
-#endif
-
-	/*
-	 * Given `idx` calculate address of ldcopr16/bx lr instruction pair
-	 * in the table below.
-	 */
-	adr	r1, 1f
-	lsl	r0, r0, #3	/* each ldcopr16/bx lr sequence is 8 bytes */
-	add	r1, r1, r0
-	bx	r1
-
-1:
-	ldcopr16	r0, r1, AMEVCNTR10	/* index 0 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR11	/* index 1 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR12	/* index 2 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR13	/* index 3 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR14	/* index 4 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR15	/* index 5 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR16	/* index 6 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR17	/* index 7 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR18	/* index 8 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR19	/* index 9 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR1A	/* index 10 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR1B	/* index 11 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR1C	/* index 12 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR1D	/* index 13 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR1E	/* index 14 */
-	bx		lr
-	ldcopr16	r0, r1, AMEVCNTR1F	/* index 15 */
-	bx		lr
-endfunc amu_group1_cnt_read_internal
-
-/*
- * void amu_group1_cnt_write_internal(int idx, uint64_t val);
- *
- * Given `idx`, write `val` to the corresponding AMU counter.
- * `idx` is passed in `r0` and `val` is passed in `r2` and `r3`.
- * `r1` is used as a scratch register.
- */
-func amu_group1_cnt_write_internal
-#if ENABLE_ASSERTIONS
-	/* `idx` should be between [0, 15] */
-	mov	r1, r0
-	lsr	r1, r1, #4
-	cmp	r1, #0
-	ASM_ASSERT(eq)
-#endif
-
-	/*
-	 * Given `idx` calculate address of ldcopr16/bx lr instruction pair
-	 * in the table below.
-	 */
-	adr	r1, 1f
-	lsl	r0, r0, #3	/* each stcopr16/bx lr sequence is 8 bytes */
-	add	r1, r1, r0
-	bx	r1
-
-1:
-	stcopr16	r2, r3, AMEVCNTR10	/* index 0 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR11	/* index 1 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR12	/* index 2 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR13	/* index 3 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR14	/* index 4 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR15	/* index 5 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR16	/* index 6 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR17	/* index 7 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR18	/* index 8 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR19	/* index 9 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR1A	/* index 10 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR1B	/* index 11 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR1C	/* index 12 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR1D	/* index 13 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR1E	/* index 14 */
-	bx		lr
-	stcopr16	r2, r3, AMEVCNTR1F	/* index 15 */
-	bx		lr
-endfunc amu_group1_cnt_write_internal
-
-/*
- * void amu_group1_set_evtype_internal(int idx, unsigned int val);
- *
- * Program the AMU event type register indexed by `idx`
- * with the value `val`.
- */
-func amu_group1_set_evtype_internal
-#if ENABLE_ASSERTIONS
-	/* `idx` should be between [0, 15] */
-	mov	r2, r0
-	lsr	r2, r2, #4
-	cmp	r2, #0
-	ASM_ASSERT(eq)
-
-	/* val should be between [0, 65535] */
-	mov	r2, r1
-	lsr	r2, r2, #16
-	cmp	r2, #0
-	ASM_ASSERT(eq)
-#endif
-
-	/*
-	 * Given `idx` calculate address of stcopr/bx lr instruction pair
-	 * in the table below.
-	 */
-	adr	r2, 1f
-	lsl	r0, r0, #3	/* each stcopr/bx lr sequence is 8 bytes */
-	add	r2, r2, r0
-	bx	r2
-
-1:
-	stcopr	r1, AMEVTYPER10 /* index 0 */
-	bx	lr
-	stcopr	r1, AMEVTYPER11 /* index 1 */
-	bx	lr
-	stcopr	r1, AMEVTYPER12 /* index 2 */
-	bx	lr
-	stcopr	r1, AMEVTYPER13 /* index 3 */
-	bx	lr
-	stcopr	r1, AMEVTYPER14 /* index 4 */
-	bx	lr
-	stcopr	r1, AMEVTYPER15 /* index 5 */
-	bx	lr
-	stcopr	r1, AMEVTYPER16 /* index 6 */
-	bx	lr
-	stcopr	r1, AMEVTYPER17 /* index 7 */
-	bx	lr
-	stcopr	r1, AMEVTYPER18 /* index 8 */
-	bx	lr
-	stcopr	r1, AMEVTYPER19 /* index 9 */
-	bx	lr
-	stcopr	r1, AMEVTYPER1A /* index 10 */
-	bx	lr
-	stcopr	r1, AMEVTYPER1B /* index 11 */
-	bx	lr
-	stcopr	r1, AMEVTYPER1C /* index 12 */
-	bx	lr
-	stcopr	r1, AMEVTYPER1D /* index 13 */
-	bx	lr
-	stcopr	r1, AMEVTYPER1E /* index 14 */
-	bx	lr
-	stcopr	r1, AMEVTYPER1F /* index 15 */
-	bx	lr
-endfunc amu_group1_set_evtype_internal
-#endif
diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c
index cb9a0f2..5f23c07 100644
--- a/lib/extensions/amu/aarch64/amu.c
+++ b/lib/extensions/amu/aarch64/amu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,183 +10,37 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include "../amu_private.h"
 #include <arch.h>
 #include <arch_features.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <lib/el3_runtime/pubsub_events.h>
 #include <lib/extensions/amu.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
 
-#include <plat/common/platform.h>
+amu_regs_t amu_ctx[PLATFORM_CORE_COUNT];
 
-#if ENABLE_AMU_FCONF
-#	include <lib/fconf/fconf.h>
-#	include <lib/fconf/fconf_amu_getter.h>
-#endif
-
-#if ENABLE_MPMM
-#	include <lib/mpmm/mpmm.h>
-#endif
-
-struct amu_ctx {
-	uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS];
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint64_t group1_cnts[AMU_GROUP1_MAX_COUNTERS];
-#endif
-
-	/* Architected event counter 1 does not have an offset register */
-	uint64_t group0_voffsets[AMU_GROUP0_MAX_COUNTERS - 1U];
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint64_t group1_voffsets[AMU_GROUP1_MAX_COUNTERS];
-#endif
-
-	uint16_t group0_enable;
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint16_t group1_enable;
-#endif
-};
-
-static struct amu_ctx amu_ctxs_[PLATFORM_CORE_COUNT];
-
-CASSERT((sizeof(amu_ctxs_[0].group0_enable) * CHAR_BIT) <= AMU_GROUP0_MAX_COUNTERS,
-	amu_ctx_group0_enable_cannot_represent_all_group0_counters);
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-CASSERT((sizeof(amu_ctxs_[0].group1_enable) * CHAR_BIT) <= AMU_GROUP1_MAX_COUNTERS,
-	amu_ctx_group1_enable_cannot_represent_all_group1_counters);
-#endif
-
-static inline __unused uint64_t read_hcr_el2_amvoffen(void)
-{
-	return (read_hcr_el2() & HCR_AMVOFFEN_BIT) >>
-		HCR_AMVOFFEN_SHIFT;
-}
-
-static inline __unused void write_cptr_el2_tam(uint64_t value)
-{
-	write_cptr_el2((read_cptr_el2() & ~CPTR_EL2_TAM_BIT) |
-		((value << CPTR_EL2_TAM_SHIFT) & CPTR_EL2_TAM_BIT));
-}
-
-static inline __unused void ctx_write_scr_el3_amvoffen(cpu_context_t *ctx, uint64_t amvoffen)
-{
-	uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_SCR_EL3);
-
-	value &= ~SCR_AMVOFFEN_BIT;
-	value |= (amvoffen << SCR_AMVOFFEN_SHIFT) & SCR_AMVOFFEN_BIT;
-
-	write_ctx_reg(get_el3state_ctx(ctx), CTX_SCR_EL3, value);
-}
-
-static inline __unused void write_hcr_el2_amvoffen(uint64_t value)
-{
-	write_hcr_el2((read_hcr_el2() & ~HCR_AMVOFFEN_BIT) |
-		((value << HCR_AMVOFFEN_SHIFT) & HCR_AMVOFFEN_BIT));
-}
-
-static inline __unused void write_amcr_el0_cg1rz(uint64_t value)
-{
-	write_amcr_el0((read_amcr_el0() & ~AMCR_CG1RZ_BIT) |
-		((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
-}
-
-static inline __unused uint64_t read_amcfgr_el0_ncg(void)
-{
-	return (read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT) &
-		AMCFGR_EL0_NCG_MASK;
-}
-
-static inline __unused uint64_t read_amcgcr_el0_cg0nc(void)
-{
-	return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) &
-		AMCGCR_EL0_CG0NC_MASK;
-}
-
-static inline __unused uint64_t read_amcg1idr_el0_voff(void)
-{
-	return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) &
-		AMCG1IDR_VOFF_MASK;
-}
-
-static inline __unused uint64_t read_amcgcr_el0_cg1nc(void)
+static inline uint8_t read_amcgcr_el0_cg1nc(void)
 {
 	return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
 		AMCGCR_EL0_CG1NC_MASK;
 }
 
-static inline __unused uint64_t read_amcntenset0_el0_px(void)
-{
-	return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) &
-		AMCNTENSET0_EL0_Pn_MASK;
-}
-
-static inline __unused uint64_t read_amcntenset1_el0_px(void)
-{
-	return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) &
-		AMCNTENSET1_EL0_Pn_MASK;
-}
-
-static inline __unused void write_amcntenset0_el0_px(uint64_t px)
-{
-	uint64_t value = read_amcntenset0_el0();
-
-	value &= ~AMCNTENSET0_EL0_Pn_MASK;
-	value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK;
-
-	write_amcntenset0_el0(value);
-}
-
-static inline __unused void write_amcntenset1_el0_px(uint64_t px)
-{
-	uint64_t value = read_amcntenset1_el0();
-
-	value &= ~AMCNTENSET1_EL0_Pn_MASK;
-	value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK;
-
-	write_amcntenset1_el0(value);
-}
-
-static inline __unused void write_amcntenclr0_el0_px(uint64_t px)
-{
-	uint64_t value = read_amcntenclr0_el0();
-
-	value &= ~AMCNTENCLR0_EL0_Pn_MASK;
-	value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK;
-
-	write_amcntenclr0_el0(value);
-}
-
-static inline __unused void write_amcntenclr1_el0_px(uint64_t px)
-{
-	uint64_t value = read_amcntenclr1_el0();
-
-	value &= ~AMCNTENCLR1_EL0_Pn_MASK;
-	value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK;
-
-	write_amcntenclr1_el0(value);
-}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-static __unused bool amu_group1_supported(void)
-{
-	return read_amcfgr_el0_ncg() > 0U;
-}
-#endif
-
-/*
- * Enable counters. This function is meant to be invoked by the context
- * management library before exiting from EL3.
- */
 void amu_enable(cpu_context_t *ctx)
 {
 	/* Initialize FEAT_AMUv1p1 features if present. */
 	if (is_feat_amuv1p1_supported()) {
+		el3_state_t *state = get_el3state_ctx(ctx);
+		u_register_t reg;
+
 		/*
 		 * Set SCR_EL3.AMVOFFEN to one so that accesses to virtual
 		 * offset registers at EL2 do not trap to EL3
 		 */
-		ctx_write_scr_el3_amvoffen(ctx, 1U);
+		reg = read_ctx_reg(state, CTX_SCR_EL3);
+		reg |= SCR_AMVOFFEN_BIT;
+		write_ctx_reg(state, CTX_SCR_EL3, reg);
 	}
 }
 
@@ -202,46 +56,18 @@
 	per_world_ctx->ctx_cptr_el3 = cptr_el3;
 }
 
-void amu_init_el3(void)
+void amu_init_el3(unsigned int core_pos)
 {
-	uint64_t group0_impl_ctr = read_amcgcr_el0_cg0nc();
-	uint64_t group0_en_mask = (1 << (group0_impl_ctr)) - 1U;
-	uint64_t num_ctr_groups = read_amcfgr_el0_ncg();
+	/* architecture is currently pinned to 4 */
+	assert((read_amcgcr_el0() & AMCGCR_EL0_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
 
 	/* Enable all architected counters by default */
-	write_amcntenset0_el0_px(group0_en_mask);
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	if (num_ctr_groups > 0U) {
-		uint64_t amcntenset1_el0_px = 0x0; /* Group 1 enable mask */
-		const struct amu_topology *topology;
-
-		/*
-		 * The platform may opt to enable specific auxiliary counters.
-		 * This can be done via the common FCONF getter, or via the
-		 * platform-implemented function.
-		 */
-#if ENABLE_AMU_FCONF
-		topology = FCONF_GET_PROPERTY(amu, config, topology);
-#else
-		topology = plat_amu_topology();
-#endif /* ENABLE_AMU_FCONF */
-
-		if (topology != NULL) {
-			unsigned int core_pos = plat_my_core_pos();
-
-			amcntenset1_el0_px = topology->cores[core_pos].enable;
-		} else {
-			ERROR("AMU: failed to generate AMU topology\n");
-		}
-
-		write_amcntenset1_el0_px(amcntenset1_el0_px);
-	}
-#else /* ENABLE_AMU_AUXILIARY_COUNTERS */
-	if (num_ctr_groups > 0U) {
-		VERBOSE("AMU: auxiliary counters detected but support is disabled\n");
+	write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
+	if (is_feat_amu_aux_supported()) {
+		/* something went wrong if we're trying to write higher bits */
+		assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_EL0_Pn_MASK) == 0);
+		write_amcntenset1_el0(get_amu_aux_enables(core_pos));
 	}
-#endif /* ENABLE_AMU_AUXILIARY_COUNTERS */
 
 	if (is_feat_amuv1p1_supported()) {
 #if AMU_RESTRICT_COUNTERS
@@ -253,15 +79,12 @@
 		 * zero. Reads from the memory mapped view are unaffected.
 		 */
 		VERBOSE("AMU group 1 counter access restricted.\n");
-		write_amcr_el0_cg1rz(1U);
+		write_amcr_el0(AMCR_CG1RZ_BIT);
 #else
-		write_amcr_el0_cg1rz(0U);
+		/* HDBG = 0 in both cases */
+		write_amcr_el0(0);
 #endif
 	}
-
-#if ENABLE_MPMM
-	mpmm_enable();
-#endif
 }
 
 void amu_init_el2_unused(void)
@@ -270,230 +93,93 @@
 	 * CPTR_EL2.TAM: Set to zero so any accesses to the Activity Monitor
 	 *  registers do not trap to EL2.
 	 */
-	write_cptr_el2_tam(0U);
+	write_cptr_el2(read_cptr_el2() & ~CPTR_EL2_TAM_BIT);
 
-	/* Initialize FEAT_AMUv1p1 features if present. */
 	if (is_feat_amuv1p1_supported()) {
-		/* Make sure virtual offsets are disabled if EL2 not used. */
-		write_hcr_el2_amvoffen(0U);
+		/* Make sure virtual offsets are disabled */
+		write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT);
 	}
 }
 
-/* Read the group 0 counter identified by the given `idx`. */
-static uint64_t amu_group0_cnt_read(unsigned int idx)
-{
-	assert(is_feat_amu_supported());
-	assert(idx < read_amcgcr_el0_cg0nc());
-
-	return amu_group0_cnt_read_internal(idx);
-}
-
-/* Write the group 0 counter identified by the given `idx` with `val` */
-static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
-{
-	assert(is_feat_amu_supported());
-	assert(idx < read_amcgcr_el0_cg0nc());
-
-	amu_group0_cnt_write_internal(idx, val);
-	isb();
-}
-
-/*
- * Unlike with auxiliary counters, we cannot detect at runtime whether an
- * architected counter supports a virtual offset. These are instead fixed
- * according to FEAT_AMUv1p1, but this switch will need to be updated if later
- * revisions of FEAT_AMU add additional architected counters.
- */
-static bool amu_group0_voffset_supported(uint64_t idx)
-{
-	switch (idx) {
-	case 0U:
-	case 2U:
-	case 3U:
-		return true;
-
-	case 1U:
-		return false;
-
-	default:
-		ERROR("AMU: can't set up virtual offset for unknown "
-		      "architected counter %" PRIu64 "!\n", idx);
-
-		panic();
-	}
-}
-
-/*
- * Read the group 0 offset register for a given index. Index must be 0, 2,
- * or 3, the register for 1 does not exist.
- *
- * Using this function requires FEAT_AMUv1p1 support.
- */
-static uint64_t amu_group0_voffset_read(unsigned int idx)
-{
-	assert(is_feat_amuv1p1_supported());
-	assert(idx < read_amcgcr_el0_cg0nc());
-	assert(idx != 1U);
-
-	return amu_group0_voffset_read_internal(idx);
-}
-
-/*
- * Write the group 0 offset register for a given index. Index must be 0, 2, or
- * 3, the register for 1 does not exist.
- *
- * Using this function requires FEAT_AMUv1p1 support.
- */
-static void amu_group0_voffset_write(unsigned int idx, uint64_t val)
-{
-	assert(is_feat_amuv1p1_supported());
-	assert(idx < read_amcgcr_el0_cg0nc());
-	assert(idx != 1U);
-
-	amu_group0_voffset_write_internal(idx, val);
-	isb();
-}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-/* Read the group 1 counter identified by the given `idx` */
-static uint64_t amu_group1_cnt_read(unsigned int idx)
-{
-	assert(is_feat_amu_supported());
-	assert(amu_group1_supported());
-	assert(idx < read_amcgcr_el0_cg1nc());
-
-	return amu_group1_cnt_read_internal(idx);
-}
-
-/* Write the group 1 counter identified by the given `idx` with `val` */
-static void amu_group1_cnt_write(unsigned int idx, uint64_t val)
-{
-	assert(is_feat_amu_supported());
-	assert(amu_group1_supported());
-	assert(idx < read_amcgcr_el0_cg1nc());
-
-	amu_group1_cnt_write_internal(idx, val);
-	isb();
-}
-
-/*
- * Read the group 1 offset register for a given index.
- *
- * Using this function requires FEAT_AMUv1p1 support.
- */
-static uint64_t amu_group1_voffset_read(unsigned int idx)
-{
-	assert(is_feat_amuv1p1_supported());
-	assert(amu_group1_supported());
-	assert(idx < read_amcgcr_el0_cg1nc());
-	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
-
-	return amu_group1_voffset_read_internal(idx);
-}
-
-/*
- * Write the group 1 offset register for a given index.
- *
- * Using this function requires FEAT_AMUv1p1 support.
- */
-static void amu_group1_voffset_write(unsigned int idx, uint64_t val)
-{
-	assert(is_feat_amuv1p1_supported());
-	assert(amu_group1_supported());
-	assert(idx < read_amcgcr_el0_cg1nc());
-	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
-
-	amu_group1_voffset_write_internal(idx, val);
-	isb();
-}
-#endif
-
 static void *amu_context_save(const void *arg)
 {
-	uint64_t i, j;
-
-	unsigned int core_pos;
-	struct amu_ctx *ctx;
-
-	uint64_t hcr_el2_amvoffen = 0;	/* AMU virtual offsets enabled */
-	uint64_t amcgcr_el0_cg0nc;	/* Number of group 0 counters */
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint64_t amcg1idr_el0_voff;	/* Auxiliary counters with virtual offsets */
-	uint64_t amcfgr_el0_ncg;	/* Number of counter groups */
-	uint64_t amcgcr_el0_cg1nc;	/* Number of group 1 counters */
-#endif
-
 	if (!is_feat_amu_supported()) {
 		return (void *)0;
 	}
-
-	core_pos = plat_my_core_pos();
-	ctx = &amu_ctxs_[core_pos];
-
-	amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
-	if (is_feat_amuv1p1_supported()) {
-		hcr_el2_amvoffen = read_hcr_el2_amvoffen();
-	}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	amcfgr_el0_ncg = read_amcfgr_el0_ncg();
-	amcgcr_el0_cg1nc = (amcfgr_el0_ncg > 0U) ? read_amcgcr_el0_cg1nc() : 0U;
-	amcg1idr_el0_voff = (hcr_el2_amvoffen != 0U) ? read_amcg1idr_el0_voff() : 0U;
-#endif
-
-	/*
-	 * Disable all AMU counters.
-	 */
-
-	ctx->group0_enable = read_amcntenset0_el0_px();
-	write_amcntenclr0_el0_px(ctx->group0_enable);
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	if (amcfgr_el0_ncg > 0U) {
-		ctx->group1_enable = read_amcntenset1_el0_px();
-		write_amcntenclr1_el0_px(ctx->group1_enable);
-	}
-#endif
 
-	/*
-	 * Save the counters to the local context.
-	 */
+	unsigned int core_pos = *(unsigned int *)arg;
+	amu_regs_t *ctx = &amu_ctx[core_pos];
 
-	isb(); /* Ensure counters have been stopped */
-
-	for (i = 0U; i < amcgcr_el0_cg0nc; i++) {
-		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
-	}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	for (i = 0U; i < amcgcr_el0_cg1nc; i++) {
-		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
+	/* disable all counters so we can write them safely later */
+	write_amcntenclr0_el0(AMCNTENCLR0_EL0_Pn_MASK);
+	if (is_feat_amu_aux_supported()) {
+		write_amcntenclr1_el0(get_amu_aux_enables(core_pos));
 	}
-#endif
 
-	/*
-	 * Save virtual offsets for counters that offer them.
-	 */
-
-	if (hcr_el2_amvoffen != 0U) {
-		for (i = 0U, j = 0U; i < amcgcr_el0_cg0nc; i++) {
-			if (!amu_group0_voffset_supported(i)) {
-				continue; /* No virtual offset */
-			}
+	isb();
 
-			ctx->group0_voffsets[j++] = amu_group0_voffset_read(i);
-		}
+	write_amu_grp0_ctx_reg(ctx, 0, read_amevcntr00_el0());
+	write_amu_grp0_ctx_reg(ctx, 1, read_amevcntr01_el0());
+	write_amu_grp0_ctx_reg(ctx, 2, read_amevcntr02_el0());
+	write_amu_grp0_ctx_reg(ctx, 3, read_amevcntr03_el0());
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-		for (i = 0U, j = 0U; i < amcgcr_el0_cg1nc; i++) {
-			if ((amcg1idr_el0_voff >> i) & 1U) {
-				continue; /* No virtual offset */
-			}
+	if (is_feat_amu_aux_supported()) {
+		uint8_t num_counters = read_amcgcr_el0_cg1nc();
 
-			ctx->group1_voffsets[j++] = amu_group1_voffset_read(i);
+		switch (num_counters) {
+		case 0x10:
+			write_amu_grp1_ctx_reg(ctx, 0xf, read_amevcntr1f_el0());
+			__fallthrough;
+		case 0x0f:
+			write_amu_grp1_ctx_reg(ctx, 0xe, read_amevcntr1e_el0());
+			__fallthrough;
+		case 0x0e:
+			write_amu_grp1_ctx_reg(ctx, 0xd, read_amevcntr1d_el0());
+			__fallthrough;
+		case 0x0d:
+			write_amu_grp1_ctx_reg(ctx, 0xc, read_amevcntr1c_el0());
+			__fallthrough;
+		case 0x0c:
+			write_amu_grp1_ctx_reg(ctx, 0xb, read_amevcntr1b_el0());
+			__fallthrough;
+		case 0x0b:
+			write_amu_grp1_ctx_reg(ctx, 0xa, read_amevcntr1a_el0());
+			__fallthrough;
+		case 0x0a:
+			write_amu_grp1_ctx_reg(ctx, 0x9, read_amevcntr19_el0());
+			__fallthrough;
+		case 0x09:
+			write_amu_grp1_ctx_reg(ctx, 0x8, read_amevcntr18_el0());
+			__fallthrough;
+		case 0x08:
+			write_amu_grp1_ctx_reg(ctx, 0x7, read_amevcntr17_el0());
+			__fallthrough;
+		case 0x07:
+			write_amu_grp1_ctx_reg(ctx, 0x6, read_amevcntr16_el0());
+			__fallthrough;
+		case 0x06:
+			write_amu_grp1_ctx_reg(ctx, 0x5, read_amevcntr15_el0());
+			__fallthrough;
+		case 0x05:
+			write_amu_grp1_ctx_reg(ctx, 0x4, read_amevcntr14_el0());
+			__fallthrough;
+		case 0x04:
+			write_amu_grp1_ctx_reg(ctx, 0x3, read_amevcntr13_el0());
+			__fallthrough;
+		case 0x03:
+			write_amu_grp1_ctx_reg(ctx, 0x2, read_amevcntr12_el0());
+			__fallthrough;
+		case 0x02:
+			write_amu_grp1_ctx_reg(ctx, 0x1, read_amevcntr11_el0());
+			__fallthrough;
+		case 0x01:
+			write_amu_grp1_ctx_reg(ctx, 0x0, read_amevcntr10_el0());
+			__fallthrough;
+		case 0x00:
+			break;
+		default:
+			assert(0); /* something is wrong */
 		}
-#endif
 	}
 
 	return (void *)0;
@@ -501,94 +187,85 @@
 
 static void *amu_context_restore(const void *arg)
 {
-	uint64_t i, j;
-
-	unsigned int core_pos;
-	struct amu_ctx *ctx;
-
-	uint64_t hcr_el2_amvoffen = 0;	/* AMU virtual offsets enabled */
-
-	uint64_t amcgcr_el0_cg0nc;	/* Number of group 0 counters */
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	uint64_t amcfgr_el0_ncg;	/* Number of counter groups */
-	uint64_t amcgcr_el0_cg1nc;	/* Number of group 1 counters */
-	uint64_t amcg1idr_el0_voff;	/* Auxiliary counters with virtual offsets */
-#endif
-
 	if (!is_feat_amu_supported()) {
 		return (void *)0;
 	}
 
-	core_pos = plat_my_core_pos();
-	ctx = &amu_ctxs_[core_pos];
-
-	amcgcr_el0_cg0nc = read_amcgcr_el0_cg0nc();
-
-	if (is_feat_amuv1p1_supported()) {
-		hcr_el2_amvoffen = read_hcr_el2_amvoffen();
-	}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	amcfgr_el0_ncg = read_amcfgr_el0_ncg();
-	amcgcr_el0_cg1nc = (amcfgr_el0_ncg > 0U) ? read_amcgcr_el0_cg1nc() : 0U;
-	amcg1idr_el0_voff = (hcr_el2_amvoffen != 0U) ? read_amcg1idr_el0_voff() : 0U;
-#endif
+	unsigned int core_pos = *(unsigned int *)arg;
+	amu_regs_t *ctx = &amu_ctx[core_pos];
 
-	/*
-	 * Restore the counter values from the local context.
-	 */
+	write_amevcntr00_el0(read_amu_grp0_ctx_reg(ctx, 0));
+	write_amevcntr01_el0(read_amu_grp0_ctx_reg(ctx, 1));
+	write_amevcntr02_el0(read_amu_grp0_ctx_reg(ctx, 2));
+	write_amevcntr03_el0(read_amu_grp0_ctx_reg(ctx, 3));
 
-	for (i = 0U; i < amcgcr_el0_cg0nc; i++) {
-		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
-	}
+	if (is_feat_amu_aux_supported()) {
+		uint8_t num_counters = read_amcgcr_el0_cg1nc();
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	for (i = 0U; i < amcgcr_el0_cg1nc; i++) {
-		amu_group1_cnt_write(i, ctx->group1_cnts[i]);
-	}
-#endif
-
-	/*
-	 * Restore virtual offsets for counters that offer them.
-	 */
-
-	if (hcr_el2_amvoffen != 0U) {
-		for (i = 0U, j = 0U; i < amcgcr_el0_cg0nc; i++) {
-			if (!amu_group0_voffset_supported(i)) {
-				continue; /* No virtual offset */
-			}
-
-			amu_group0_voffset_write(i, ctx->group0_voffsets[j++]);
-		}
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-		for (i = 0U, j = 0U; i < amcgcr_el0_cg1nc; i++) {
-			if ((amcg1idr_el0_voff >> i) & 1U) {
-				continue; /* No virtual offset */
-			}
-
-			amu_group1_voffset_write(i, ctx->group1_voffsets[j++]);
+		switch (num_counters) {
+		case 0x10:
+			write_amevcntr1f_el0(read_amu_grp1_ctx_reg(ctx, 0xf));
+			__fallthrough;
+		case 0x0f:
+			write_amevcntr1e_el0(read_amu_grp1_ctx_reg(ctx, 0xe));
+			__fallthrough;
+		case 0x0e:
+			write_amevcntr1d_el0(read_amu_grp1_ctx_reg(ctx, 0xd));
+			__fallthrough;
+		case 0x0d:
+			write_amevcntr1c_el0(read_amu_grp1_ctx_reg(ctx, 0xc));
+			__fallthrough;
+		case 0x0c:
+			write_amevcntr1b_el0(read_amu_grp1_ctx_reg(ctx, 0xb));
+			__fallthrough;
+		case 0x0b:
+			write_amevcntr1a_el0(read_amu_grp1_ctx_reg(ctx, 0xa));
+			__fallthrough;
+		case 0x0a:
+			write_amevcntr19_el0(read_amu_grp1_ctx_reg(ctx, 0x9));
+			__fallthrough;
+		case 0x09:
+			write_amevcntr18_el0(read_amu_grp1_ctx_reg(ctx, 0x8));
+			__fallthrough;
+		case 0x08:
+			write_amevcntr17_el0(read_amu_grp1_ctx_reg(ctx, 0x7));
+			__fallthrough;
+		case 0x07:
+			write_amevcntr16_el0(read_amu_grp1_ctx_reg(ctx, 0x6));
+			__fallthrough;
+		case 0x06:
+			write_amevcntr15_el0(read_amu_grp1_ctx_reg(ctx, 0x5));
+			__fallthrough;
+		case 0x05:
+			write_amevcntr14_el0(read_amu_grp1_ctx_reg(ctx, 0x4));
+			__fallthrough;
+		case 0x04:
+			write_amevcntr13_el0(read_amu_grp1_ctx_reg(ctx, 0x3));
+			__fallthrough;
+		case 0x03:
+			write_amevcntr12_el0(read_amu_grp1_ctx_reg(ctx, 0x2));
+			__fallthrough;
+		case 0x02:
+			write_amevcntr11_el0(read_amu_grp1_ctx_reg(ctx, 0x1));
+			__fallthrough;
+		case 0x01:
+			write_amevcntr10_el0(read_amu_grp1_ctx_reg(ctx, 0x0));
+			__fallthrough;
+		case 0x00:
+			break;
+		default:
+			assert(0); /* something is wrong */
 		}
-#endif
 	}
 
-	/*
-	 * Re-enable counters that were disabled during context save.
-	 */
-
-	write_amcntenset0_el0_px(ctx->group0_enable);
 
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-	if (amcfgr_el0_ncg > 0) {
-		write_amcntenset1_el0_px(ctx->group1_enable);
+	/* now enable them again */
+	write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
+	if (is_feat_amu_aux_supported()) {
+		write_amcntenset1_el0(get_amu_aux_enables(core_pos));
 	}
-#endif
 
-#if ENABLE_MPMM
-	mpmm_enable();
-#endif
-
+	isb();
 	return (void *)0;
 }
 
diff --git a/lib/extensions/amu/aarch64/amu_helpers.S b/lib/extensions/amu/aarch64/amu_helpers.S
deleted file mode 100644
index 95d4ad6..0000000
--- a/lib/extensions/amu/aarch64/amu_helpers.S
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <assert_macros.S>
-#include <asm_macros.S>
-
-	.globl	amu_group0_cnt_read_internal
-	.globl	amu_group0_cnt_write_internal
-	.globl	amu_group1_cnt_read_internal
-	.globl	amu_group1_cnt_write_internal
-	.globl	amu_group1_set_evtype_internal
-
-	/* FEAT_AMUv1p1 virtualisation offset register functions */
-	.globl	amu_group0_voffset_read_internal
-	.globl	amu_group0_voffset_write_internal
-	.globl	amu_group1_voffset_read_internal
-	.globl	amu_group1_voffset_write_internal
-
-/*
- * uint64_t amu_group0_cnt_read_internal(int idx);
- *
- * Given `idx`, read the corresponding AMU counter
- * and return it in `x0`.
- */
-func amu_group0_cnt_read_internal
-	adr	x1, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~3
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x1
-
-1:	read	AMEVCNTR00_EL0		/* index 0 */
-	read	AMEVCNTR01_EL0		/* index 1 */
-	read	AMEVCNTR02_EL0		/* index 2 */
-	read	AMEVCNTR03_EL0		/* index 3 */
-endfunc amu_group0_cnt_read_internal
-
-/*
- * void amu_group0_cnt_write_internal(int idx, uint64_t val);
- *
- * Given `idx`, write `val` to the corresponding AMU counter.
- */
-func amu_group0_cnt_write_internal
-	adr	x2, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~3
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x2
-
-1:	write	AMEVCNTR00_EL0		/* index 0 */
-	write	AMEVCNTR01_EL0		/* index 1 */
-	write	AMEVCNTR02_EL0		/* index 2 */
-	write	AMEVCNTR03_EL0		/* index 3 */
-endfunc amu_group0_cnt_write_internal
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-/*
- * uint64_t amu_group1_cnt_read_internal(int idx);
- *
- * Given `idx`, read the corresponding AMU counter
- * and return it in `x0`.
- */
-func amu_group1_cnt_read_internal
-	adr	x1, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~0xF
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x1
-
-1:	read	AMEVCNTR10_EL0		/* index 0 */
-	read	AMEVCNTR11_EL0		/* index 1 */
-	read	AMEVCNTR12_EL0		/* index 2 */
-	read	AMEVCNTR13_EL0		/* index 3 */
-	read	AMEVCNTR14_EL0		/* index 4 */
-	read	AMEVCNTR15_EL0		/* index 5 */
-	read	AMEVCNTR16_EL0		/* index 6 */
-	read	AMEVCNTR17_EL0		/* index 7 */
-	read	AMEVCNTR18_EL0		/* index 8 */
-	read	AMEVCNTR19_EL0		/* index 9 */
-	read	AMEVCNTR1A_EL0		/* index 10 */
-	read	AMEVCNTR1B_EL0		/* index 11 */
-	read	AMEVCNTR1C_EL0		/* index 12 */
-	read	AMEVCNTR1D_EL0		/* index 13 */
-	read	AMEVCNTR1E_EL0		/* index 14 */
-	read	AMEVCNTR1F_EL0		/* index 15 */
-endfunc amu_group1_cnt_read_internal
-
-/*
- * void amu_group1_cnt_write_internal(int idx, uint64_t val);
- *
- * Given `idx`, write `val` to the corresponding AMU counter.
- */
-func amu_group1_cnt_write_internal
-	adr	x2, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~0xF
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x2
-
-1:	write	AMEVCNTR10_EL0		/* index 0 */
-	write	AMEVCNTR11_EL0		/* index 1 */
-	write	AMEVCNTR12_EL0		/* index 2 */
-	write	AMEVCNTR13_EL0		/* index 3 */
-	write	AMEVCNTR14_EL0		/* index 4 */
-	write	AMEVCNTR15_EL0		/* index 5 */
-	write	AMEVCNTR16_EL0		/* index 6 */
-	write	AMEVCNTR17_EL0		/* index 7 */
-	write	AMEVCNTR18_EL0		/* index 8 */
-	write	AMEVCNTR19_EL0		/* index 9 */
-	write	AMEVCNTR1A_EL0		/* index 10 */
-	write	AMEVCNTR1B_EL0		/* index 11 */
-	write	AMEVCNTR1C_EL0		/* index 12 */
-	write	AMEVCNTR1D_EL0		/* index 13 */
-	write	AMEVCNTR1E_EL0		/* index 14 */
-	write	AMEVCNTR1F_EL0		/* index 15 */
-endfunc amu_group1_cnt_write_internal
-
-/*
- * void amu_group1_set_evtype_internal(int idx, unsigned int val);
- *
- * Program the AMU event type register indexed by `idx`
- * with the value `val`.
- */
-func amu_group1_set_evtype_internal
-	adr	x2, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~0xF
-	ASM_ASSERT(eq)
-
-	/* val should be between [0, 65535] */
-	tst	x1, #~0xFFFF
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of msr/ret instruction pair
-	 * in the table below.
-	 */
-	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x2
-
-1:	write	AMEVTYPER10_EL0		/* index 0 */
-	write	AMEVTYPER11_EL0		/* index 1 */
-	write	AMEVTYPER12_EL0		/* index 2 */
-	write	AMEVTYPER13_EL0		/* index 3 */
-	write	AMEVTYPER14_EL0		/* index 4 */
-	write	AMEVTYPER15_EL0		/* index 5 */
-	write	AMEVTYPER16_EL0		/* index 6 */
-	write	AMEVTYPER17_EL0		/* index 7 */
-	write	AMEVTYPER18_EL0		/* index 8 */
-	write	AMEVTYPER19_EL0		/* index 9 */
-	write	AMEVTYPER1A_EL0		/* index 10 */
-	write	AMEVTYPER1B_EL0		/* index 11 */
-	write	AMEVTYPER1C_EL0		/* index 12 */
-	write	AMEVTYPER1D_EL0		/* index 13 */
-	write	AMEVTYPER1E_EL0		/* index 14 */
-	write	AMEVTYPER1F_EL0		/* index 15 */
-endfunc amu_group1_set_evtype_internal
-#endif
-
-/*
- * Accessor functions for virtual offset registers added with FEAT_AMUv1p1
- */
-
-/*
- * uint64_t amu_group0_voffset_read_internal(int idx);
- *
- * Given `idx`, read the corresponding AMU virtual offset register
- * and return it in `x0`.
- */
-func amu_group0_voffset_read_internal
-	adr	x1, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~3
-	ASM_ASSERT(eq)
-	/* Make sure idx != 1 since AMEVCNTVOFF01_EL2 does not exist */
-	cmp	x0, #1
-	ASM_ASSERT(ne)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x1
-
-1:	read	AMEVCNTVOFF00_EL2	/* index 0 */
-	.skip	8			/* AMEVCNTVOFF01_EL2 does not exist */
-#if ENABLE_BTI
-	.skip	4
-#endif
-	read	AMEVCNTVOFF02_EL2	/* index 2 */
-	read	AMEVCNTVOFF03_EL2	/* index 3 */
-endfunc amu_group0_voffset_read_internal
-
-/*
- * void amu_group0_voffset_write_internal(int idx, uint64_t val);
- *
- * Given `idx`, write `val` to the corresponding AMU virtual offset register.
- */
-func amu_group0_voffset_write_internal
-	adr	x2, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~3
-	ASM_ASSERT(eq)
-	/* Make sure idx != 1 since AMEVCNTVOFF01_EL2 does not exist */
-	cmp	x0, #1
-	ASM_ASSERT(ne)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x2
-
-1:	write	AMEVCNTVOFF00_EL2	/* index 0 */
-	.skip	8			/* AMEVCNTVOFF01_EL2 does not exist */
-#if ENABLE_BTI
-	.skip	4
-#endif
-	write	AMEVCNTVOFF02_EL2	/* index 2 */
-	write	AMEVCNTVOFF03_EL2	/* index 3 */
-endfunc amu_group0_voffset_write_internal
-
-#if ENABLE_AMU_AUXILIARY_COUNTERS
-/*
- * uint64_t amu_group1_voffset_read_internal(int idx);
- *
- * Given `idx`, read the corresponding AMU virtual offset register
- * and return it in `x0`.
- */
-func amu_group1_voffset_read_internal
-	adr	x1, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~0xF
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x1
-
-1:	read	AMEVCNTVOFF10_EL2	/* index 0 */
-	read	AMEVCNTVOFF11_EL2	/* index 1 */
-	read	AMEVCNTVOFF12_EL2	/* index 2 */
-	read	AMEVCNTVOFF13_EL2	/* index 3 */
-	read	AMEVCNTVOFF14_EL2	/* index 4 */
-	read	AMEVCNTVOFF15_EL2	/* index 5 */
-	read	AMEVCNTVOFF16_EL2	/* index 6 */
-	read	AMEVCNTVOFF17_EL2	/* index 7 */
-	read	AMEVCNTVOFF18_EL2	/* index 8 */
-	read	AMEVCNTVOFF19_EL2	/* index 9 */
-	read	AMEVCNTVOFF1A_EL2	/* index 10 */
-	read	AMEVCNTVOFF1B_EL2	/* index 11 */
-	read	AMEVCNTVOFF1C_EL2	/* index 12 */
-	read	AMEVCNTVOFF1D_EL2	/* index 13 */
-	read	AMEVCNTVOFF1E_EL2	/* index 14 */
-	read	AMEVCNTVOFF1F_EL2	/* index 15 */
-endfunc amu_group1_voffset_read_internal
-
-/*
- * void amu_group1_voffset_write_internal(int idx, uint64_t val);
- *
- * Given `idx`, write `val` to the corresponding AMU virtual offset register.
- */
-func amu_group1_voffset_write_internal
-	adr	x2, 1f
-#if ENABLE_ASSERTIONS
-	/*
-	 * It can be dangerous to call this function with an
-	 * out of bounds index.  Ensure `idx` is valid.
-	 */
-	tst	x0, #~0xF
-	ASM_ASSERT(eq)
-#endif
-	/*
-	 * Given `idx` calculate address of mrs/ret instruction pair
-	 * in the table below.
-	 */
-	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
-#if ENABLE_BTI
-	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
-#endif
-	br	x2
-
-1:	write	AMEVCNTVOFF10_EL2	/* index 0 */
-	write	AMEVCNTVOFF11_EL2	/* index 1 */
-	write	AMEVCNTVOFF12_EL2	/* index 2 */
-	write	AMEVCNTVOFF13_EL2	/* index 3 */
-	write	AMEVCNTVOFF14_EL2	/* index 4 */
-	write	AMEVCNTVOFF15_EL2	/* index 5 */
-	write	AMEVCNTVOFF16_EL2	/* index 6 */
-	write	AMEVCNTVOFF17_EL2	/* index 7 */
-	write	AMEVCNTVOFF18_EL2	/* index 8 */
-	write	AMEVCNTVOFF19_EL2	/* index 9 */
-	write	AMEVCNTVOFF1A_EL2	/* index 10 */
-	write	AMEVCNTVOFF1B_EL2	/* index 11 */
-	write	AMEVCNTVOFF1C_EL2	/* index 12 */
-	write	AMEVCNTVOFF1D_EL2	/* index 13 */
-	write	AMEVCNTVOFF1E_EL2	/* index 14 */
-	write	AMEVCNTVOFF1F_EL2	/* index 15 */
-endfunc amu_group1_voffset_write_internal
-#endif
diff --git a/lib/extensions/amu/amu.mk b/lib/extensions/amu/amu.mk
index 868ab12..fba2c78 100644
--- a/lib/extensions/amu/amu.mk
+++ b/lib/extensions/amu/amu.mk
@@ -1,24 +1,13 @@
 #
-# Copyright (c) 2021, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
-include lib/fconf/fconf.mk
-
-AMU_SOURCES	:=	lib/extensions/amu/${ARCH}/amu.c \
-			lib/extensions/amu/${ARCH}/amu_helpers.S
+AMU_SOURCES	:=	lib/extensions/amu/${ARCH}/amu.c
 
 ifneq (${ENABLE_AMU_AUXILIARY_COUNTERS},0)
         ifeq (${ENABLE_FEAT_AMU},0)
-                $(error AMU auxiliary counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`) requires AMU support (`ENABLE_FEAT_AMU`))
-        endif
-endif
-
-ifneq (${ENABLE_AMU_FCONF},0)
-        ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0)
-                $(error AMU FCONF support (`ENABLE_AMU_FCONF`) is not necessary when auxiliary counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`) is disabled)
+                $(error "ENABLE_AMU_AUXILIARY_COUNTERS requires ENABLE_FEAT_AMU")
         endif
-
-        AMU_SOURCES	+=	${FCONF_AMU_SOURCES}
 endif
diff --git a/lib/extensions/amu/amu_private.h b/lib/extensions/amu/amu_private.h
deleted file mode 100644
index a3b6845..0000000
--- a/lib/extensions/amu/amu_private.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef AMU_PRIVATE_H
-#define AMU_PRIVATE_H
-
-#include <stdint.h>
-
-#include <lib/cassert.h>
-#include <lib/extensions/amu.h>
-#include <lib/utils_def.h>
-
-#include <platform_def.h>
-
-#define AMU_GROUP0_MAX_COUNTERS		U(16)
-#define AMU_GROUP1_MAX_COUNTERS		U(16)
-
-#define AMU_AMCGCR_CG0NC_MAX		U(16)
-
-uint64_t amu_group0_cnt_read_internal(unsigned int idx);
-void amu_group0_cnt_write_internal(unsigned int idx, uint64_t val);
-
-uint64_t amu_group1_cnt_read_internal(unsigned int idx);
-void amu_group1_cnt_write_internal(unsigned int idx, uint64_t val);
-void amu_group1_set_evtype_internal(unsigned int idx, unsigned int val);
-
-#if __aarch64__
-uint64_t amu_group0_voffset_read_internal(unsigned int idx);
-void amu_group0_voffset_write_internal(unsigned int idx, uint64_t val);
-
-uint64_t amu_group1_voffset_read_internal(unsigned int idx);
-void amu_group1_voffset_write_internal(unsigned int idx, uint64_t val);
-#endif
-
-#endif /* AMU_PRIVATE_H */
diff --git a/lib/extensions/sme/sme.c b/lib/extensions/sme/sme.c
index 98d57e9..e477da3 100644
--- a/lib/extensions/sme/sme.c
+++ b/lib/extensions/sme/sme.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -40,13 +40,8 @@
 
 void sme_init_el3(void)
 {
-	u_register_t cptr_el3 = read_cptr_el3();
 	u_register_t smcr_el3;
 
-	/* Set CPTR_EL3.ESM bit so we can access SMCR_EL3 without trapping. */
-	write_cptr_el3(cptr_el3 | ESM_BIT);
-	isb();
-
 	/*
 	 * Set the max LEN value and FA64 bit. This register is set up per_world
 	 * to be the least restrictive, then lower ELs can restrict as needed
@@ -69,10 +64,6 @@
 		smcr_el3 |= SMCR_ELX_EZT0_BIT;
 	}
 	write_smcr_el3(smcr_el3);
-
-	/* Reset CPTR_EL3 value. */
-	write_cptr_el3(cptr_el3);
-	isb();
 }
 
 void sme_init_el2_unused(void)
diff --git a/lib/extensions/sve/sve.c b/lib/extensions/sve/sve.c
index 143717e..4e18cdf 100644
--- a/lib/extensions/sve/sve.c
+++ b/lib/extensions/sve/sve.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,6 +22,12 @@
  */
 #define CONVERT_SVE_LENGTH(x)	(((x / 128) - 1))
 
+void sve_init_el3(void)
+{
+	/* Restrict maximum SVE vector length (SVE_VECTOR_LEN+1) * 128. */
+	write_zcr_el3(ZCR_EL3_LEN_MASK & CONVERT_SVE_LENGTH(SVE_VECTOR_LEN));
+}
+
 void sve_enable_per_world(per_world_context_t *per_world_ctx)
 {
 	u_register_t cptr_el3;
@@ -30,9 +36,6 @@
 	cptr_el3 = per_world_ctx->ctx_cptr_el3;
 	cptr_el3 = (cptr_el3 | CPTR_EZ_BIT) & ~(TFP_BIT);
 	per_world_ctx->ctx_cptr_el3 = cptr_el3;
-
-	/* Restrict maximum SVE vector length (SVE_VECTOR_LEN+1) * 128. */
-	per_world_ctx->ctx_zcr_el3 = (ZCR_EL3_LEN_MASK & CONVERT_SVE_LENGTH(SVE_VECTOR_LEN));
 }
 
 void sve_init_el2_unused(void)
diff --git a/lib/fconf/fconf.mk b/lib/fconf/fconf.mk
index ff781aa..d24f86b 100644
--- a/lib/fconf/fconf.mk
+++ b/lib/fconf/fconf.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -11,9 +11,3 @@
 
 FCONF_DYN_SOURCES	:=	lib/fconf/fconf_dyn_cfg_getter.c
 FCONF_DYN_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
-
-FCONF_AMU_SOURCES	:=	lib/fconf/fconf_amu_getter.c
-FCONF_AMU_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
-
-FCONF_MPMM_SOURCES	:=	lib/fconf/fconf_mpmm_getter.c
-FCONF_MPMM_SOURCES	+=	${FDT_WRAPPERS_SOURCES}
diff --git a/lib/fconf/fconf_amu_getter.c b/lib/fconf/fconf_amu_getter.c
deleted file mode 100644
index eff309c..0000000
--- a/lib/fconf/fconf_amu_getter.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <common/debug.h>
-#include <common/fdt_wrappers.h>
-#include <lib/fconf/fconf.h>
-#include <lib/fconf/fconf_amu_getter.h>
-#include <libfdt.h>
-
-#include <plat/common/platform.h>
-
-struct fconf_amu_config fconf_amu_config;
-static struct amu_topology fconf_amu_topology_;
-
-/*
- * Populate the core-specific AMU structure with information retrieved from a
- * device tree.
- *
- * Returns `0` on success, or a negative integer representing an error code.
- */
-static int fconf_populate_amu_cpu_amu(const void *fdt, int parent,
-				      struct amu_core *amu)
-{
-	int ret = 0;
-	int node = 0;
-
-	fdt_for_each_subnode(node, fdt, parent) {
-		const char *name;
-		const char *value;
-		int len;
-
-		uintptr_t idx = 0U;
-
-		name = fdt_get_name(fdt, node, &len);
-		if (strncmp(name, "counter@", 8) != 0) {
-			continue;
-		}
-
-		ret = fdt_get_reg_props_by_index(fdt, node, 0, &idx, NULL);
-		if (ret < 0) {
-			break;
-		}
-
-		value = fdt_getprop(fdt, node, "enable-at-el3", &len);
-		if ((value == NULL) && (len != -FDT_ERR_NOTFOUND)) {
-			break;
-		}
-
-		if (len != -FDT_ERR_NOTFOUND) {
-			amu->enable |= (1 << idx);
-		}
-	}
-
-	if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
-		return node;
-	}
-
-	return ret;
-}
-
-/*
- * Within a `cpu` node, attempt to dereference the `amu` property, and populate
- * the AMU information for the core.
- *
- * Returns `0` on success, or a negative integer representing an error code.
- */
-static int fconf_populate_amu_cpu(const void *fdt, int node, uintptr_t mpidr)
-{
-	int ret;
-	int idx;
-
-	uint32_t amu_phandle;
-	struct amu_core *amu;
-
-	ret = fdt_read_uint32(fdt, node, "amu", &amu_phandle);
-	if (ret < 0) {
-		if (ret == -FDT_ERR_NOTFOUND) {
-			ret = 0;
-		}
-
-		return ret;
-	}
-
-	node = fdt_node_offset_by_phandle(fdt, amu_phandle);
-	if (node < 0) {
-		return node;
-	}
-
-	idx = plat_core_pos_by_mpidr(mpidr);
-	if (idx < 0) {
-		return -FDT_ERR_BADVALUE;
-	}
-
-	amu = &fconf_amu_topology_.cores[idx];
-
-	return fconf_populate_amu_cpu_amu(fdt, node, amu);
-}
-
-/*
- * Populates the global `amu_topology` structure based on what's described by
- * the hardware configuration device tree blob.
- *
- * The device tree is expected to provide an `amu` property for each `cpu` node,
- * like so:
- *
- *     cpu@0 {
- *         amu = <&cpu0_amu>;
- *     };
- *
- *     amus {
- *         cpu0_amu: amu-0 {
- *             counters {
- *                 #address-cells = <2>;
- *                 #size-cells = <0>;
- *
- *                 counter@x,y {
- *                     reg = <x y>; // Group x, counter y
- *                 };
- *             };
- *         };
- *     };
- */
-static int fconf_populate_amu(uintptr_t config)
-{
-	int ret = fdtw_for_each_cpu(
-		(const void *)config, fconf_populate_amu_cpu);
-	if (ret == 0) {
-		fconf_amu_config.topology = &fconf_amu_topology_;
-	} else {
-		ERROR("FCONF: failed to parse AMU information: %d\n", ret);
-	}
-
-	return ret;
-}
-
-FCONF_REGISTER_POPULATOR(HW_CONFIG, amu, fconf_populate_amu);
diff --git a/lib/fconf/fconf_mpmm_getter.c b/lib/fconf/fconf_mpmm_getter.c
deleted file mode 100644
index 02a566d..0000000
--- a/lib/fconf/fconf_mpmm_getter.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <common/debug.h>
-#include <common/fdt_wrappers.h>
-#include <lib/fconf/fconf.h>
-#include <lib/fconf/fconf_mpmm_getter.h>
-#include <libfdt.h>
-
-#include <plat/common/platform.h>
-
-struct fconf_mpmm_config fconf_mpmm_config;
-static struct mpmm_topology fconf_mpmm_topology;
-
-/*
- * Within a `cpu` node, determine support for MPMM via the `supports-mpmm`
- * property.
- *
- * Returns `0` on success, or a negative integer representing an error code.
- */
-static int fconf_populate_mpmm_cpu(const void *fdt, int off, uintptr_t mpidr)
-{
-	int ret, len;
-
-	int core_pos;
-	struct mpmm_core *core;
-
-	core_pos = plat_core_pos_by_mpidr(mpidr);
-	if (core_pos < 0) {
-		return -FDT_ERR_BADVALUE;
-	}
-
-	core = &fconf_mpmm_topology.cores[core_pos];
-
-	fdt_getprop(fdt, off, "supports-mpmm", &len);
-	if (len >= 0) {
-		core->supported = true;
-		ret = 0;
-	} else {
-		core->supported = false;
-		ret = len;
-	}
-
-	return ret;
-}
-
-/*
- * Populates the global `fconf_mpmm_config` structure based on what's described
- * by the hardware configuration device tree blob.
- *
- * The device tree is expected to provide a `supports-mpmm` property for each
- * `cpu` node, like so:
- *
- *     cpu@0 {
- *       supports-mpmm;
- *     };
- *
- * This property indicates whether the core implements MPMM, as we cannot detect
- * support for it dynamically.
- */
-static int fconf_populate_mpmm(uintptr_t config)
-{
-	int ret = fdtw_for_each_cpu(
-		(const void *)config, fconf_populate_mpmm_cpu);
-	if (ret == 0) {
-		fconf_mpmm_config.topology = &fconf_mpmm_topology;
-	} else {
-		ERROR("FCONF: failed to configure MPMM: %d\n", ret);
-	}
-
-	return ret;
-}
-
-FCONF_REGISTER_POPULATOR(HW_CONFIG, mpmm, fconf_populate_mpmm);
diff --git a/lib/gpt_rme/gpt_rme.c b/lib/gpt_rme/gpt_rme.c
index 79c4ea5..115f50d 100644
--- a/lib/gpt_rme/gpt_rme.c
+++ b/lib/gpt_rme/gpt_rme.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,14 +12,13 @@
 
 #include <arch.h>
 #include <arch_features.h>
-#include <arch_helpers.h>
 #include <common/debug.h>
-#include "gpt_rme_private.h"
 #include <lib/gpt_rme/gpt_rme.h>
 #include <lib/smccc.h>
-#include <lib/spinlock.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
+#include "gpt_rme_private.h"
+
 #if !ENABLE_RME
 #error "ENABLE_RME must be enabled to use the GPT library"
 #endif
@@ -123,25 +122,19 @@
 #define GPT_L1_INDEX(_pa)	\
 	(((_pa) >> (unsigned int)GPT_L1_IDX_SHIFT(gpt_config.p)) & gpt_l1_index_mask)
 
-/* These variables are used during initialization of the L1 tables */
+/* This variable is used during initialization of the L1 tables */
 static uintptr_t gpt_l1_tbl;
 
-/* These variable is used during runtime */
+/* These variables are used during runtime */
 #if (RME_GPT_BITLOCK_BLOCK == 0)
 /*
  * The GPTs are protected by a global spinlock to ensure
  * that multiple CPUs do not attempt to change the descriptors at once.
  */
 static spinlock_t gpt_lock;
-#else
 
-/* Bitlocks base address */
-static bitlock_t *gpt_bitlock_base;
-#endif
-
-/* Lock/unlock macros for GPT entries */
-#if (RME_GPT_BITLOCK_BLOCK == 0)
-/*
+/* Lock/unlock macros for GPT entries
+ *
  * Access to GPT is controlled by a global lock to ensure
  * that no more than one CPU is allowed to make changes at any
  * given time.
@@ -149,13 +142,17 @@
 #define GPT_LOCK	spin_lock(&gpt_lock)
 #define GPT_UNLOCK	spin_unlock(&gpt_lock)
 #else
+
+/* Base address of bitlocks array */
+static bitlock_t *gpt_bitlock;
+
 /*
  * Access to a block of memory is controlled by a bitlock.
  * Size of block = RME_GPT_BITLOCK_BLOCK * 512MB.
  */
 #define GPT_LOCK	bit_lock(gpi_info.lock, gpi_info.mask)
 #define GPT_UNLOCK	bit_unlock(gpi_info.lock, gpi_info.mask)
-#endif
+#endif /* RME_GPT_BITLOCK_BLOCK */
 
 static void tlbi_page_dsbosh(uintptr_t base)
 {
@@ -494,8 +491,8 @@
  * This function validates L0 initialization parameters.
  *
  * Parameters
- *   l0_mem_base	Base address of memory used for L0 tables.
- *   l0_mem_size	Size of memory available for L0 tables.
+ *   l0_mem_base	Base address of memory used for L0 table.
+ *   l0_mem_size	Size of memory available for L0 table.
  *
  * Return
  *   Negative Linux error code in the event of a failure, 0 for success.
@@ -503,7 +500,7 @@
 static int validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
 				size_t l0_mem_size)
 {
-	size_t l0_alignment, locks_size = 0;
+	size_t l0_alignment;
 
 	/*
 	 * Make sure PPS is valid and then store it since macros need this value
@@ -516,8 +513,8 @@
 	gpt_config.pps = pps;
 	gpt_config.t = gpt_t_lookup[pps];
 
-	/* Alignment must be the greater of 4KB or l0 table size */
-	l0_alignment = PAGE_SIZE_4KB;
+	/* Alignment must be the greater of 4KB or L0 table size */
+	l0_alignment = SZ_4K;
 	if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) {
 		l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t);
 	}
@@ -529,28 +526,11 @@
 		return -EFAULT;
 	}
 
-#if (RME_GPT_BITLOCK_BLOCK != 0)
-	/*
-	 * Size of bitlocks in bytes for the protected address space
-	 * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
-	 */
-	locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
-			(RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
-
-	/*
-	 * If protected space size is less than the size covered
-	 * by 'bitlock' structure, check for a single bitlock.
-	 */
-	if (locks_size < LOCK_SIZE) {
-		locks_size = LOCK_SIZE;
-	}
-#endif
-	/* Check size for L0 tables and bitlocks */
-	if (l0_mem_size < (GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size)) {
+	/* Check memory size for L0 table */
+	if (l0_mem_size < GPT_L0_TABLE_SIZE(gpt_config.t)) {
 		ERROR("GPT: Inadequate L0 memory\n");
-		ERROR("      Expected 0x%lx bytes, got 0x%lx bytes\n",
-			GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size,
-			l0_mem_size);
+		ERROR("      Expected 0x%lx bytes, got 0x%lx\n",
+				GPT_L0_TABLE_SIZE(gpt_config.t), l0_mem_size);
 		return -ENOMEM;
 	}
 
@@ -600,7 +580,7 @@
 	if (l1_mem_size < l1_gpt_mem_sz) {
 		ERROR("%sL1 GPTs%s", (const char *)"GPT: Inadequate ",
 			(const char *)" memory\n");
-		ERROR("      Expected 0x%lx bytes, got 0x%lx bytes\n",
+		ERROR("      Expected 0x%lx bytes, got 0x%lx\n",
 			l1_gpt_mem_sz, l1_mem_size);
 		return -ENOMEM;
 	}
@@ -623,7 +603,7 @@
 	unsigned long idx, end_idx;
 	uint64_t *l0_gpt_arr;
 
-	assert(gpt_config.plat_gpt_l0_base != 0U);
+	assert(gpt_config.plat_gpt_l0_base != 0UL);
 	assert(pas != NULL);
 
 	/*
@@ -928,7 +908,7 @@
 	uint64_t *l1_gpt_arr;
 	unsigned int l0_idx, gpi;
 
-	assert(gpt_config.plat_gpt_l0_base != 0U);
+	assert(gpt_config.plat_gpt_l0_base != 0UL);
 	assert(pas != NULL);
 
 	/*
@@ -1121,12 +1101,10 @@
 		       size_t l0_mem_size)
 {
 	uint64_t gpt_desc;
-	size_t locks_size = 0;
-	__unused bitlock_t *bit_locks;
 	int ret;
 
 	/* Ensure that MMU and Data caches are enabled */
-	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
 
 	/* Validate other parameters */
 	ret = validate_l0_params(pps, l0_mem_base, l0_mem_size);
@@ -1141,32 +1119,9 @@
 	for (unsigned int i = 0U; i < GPT_L0_REGION_COUNT(gpt_config.t); i++) {
 		((uint64_t *)l0_mem_base)[i] = gpt_desc;
 	}
-
-#if (RME_GPT_BITLOCK_BLOCK != 0)
-	/* Initialise bitlocks at the end of L0 table */
-	bit_locks = (bitlock_t *)(l0_mem_base +
-					GPT_L0_TABLE_SIZE(gpt_config.t));
-
-	/* Size of bitlocks in bytes */
-	locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
-					(RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
-
-	/*
-	 * If protected space size is less than the size covered
-	 * by 'bitlock' structure, initialise a single bitlock.
-	 */
-	if (locks_size < LOCK_SIZE) {
-		locks_size = LOCK_SIZE;
-	}
-
-	for (size_t i = 0UL; i < (locks_size/LOCK_SIZE); i++) {
-		bit_locks[i].lock = 0U;
-	}
-#endif
 
-	/* Flush updated L0 tables and bitlocks to memory */
-	flush_dcache_range((uintptr_t)l0_mem_base,
-				GPT_L0_TABLE_SIZE(gpt_config.t) + locks_size);
+	/* Flush updated L0 table to memory */
+	flush_dcache_range((uintptr_t)l0_mem_base, GPT_L0_TABLE_SIZE(gpt_config.t));
 
 	/* Stash the L0 base address once initial setup is complete */
 	gpt_config.plat_gpt_l0_base = l0_mem_base;
@@ -1202,7 +1157,7 @@
 	int l1_gpt_cnt, ret;
 
 	/* Ensure that MMU and Data caches are enabled */
-	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
 
 	/* PGS is needed for validate_pas_mappings so check it now */
 	if (pgs > GPT_PGS_MAX) {
@@ -1213,7 +1168,7 @@
 	gpt_config.p = gpt_p_lookup[pgs];
 
 	/* Make sure L0 tables have been initialized */
-	if (gpt_config.plat_gpt_l0_base == 0U) {
+	if (gpt_config.plat_gpt_l0_base == 0UL) {
 		ERROR("GPT: L0 tables must be initialized first!\n");
 		return -EPERM;
 	}
@@ -1295,18 +1250,23 @@
  * initialization from a previous stage. Granule protection checks must be
  * enabled already or this function will return an error.
  *
+ * Parameters
+ *   l1_bitlocks_base	Base address of memory for L1 tables bitlocks.
+ *   l1_bitlocks_size	Total size of memory available for L1 tables bitlocks.
+ *
  * Return
  *   Negative Linux error code in the event of a failure, 0 for success.
  */
-int gpt_runtime_init(void)
+int gpt_runtime_init(uintptr_t l1_bitlocks_base, size_t l1_bitlocks_size)
 {
 	u_register_t reg;
+	__unused size_t locks_size;
 
 	/* Ensure that MMU and Data caches are enabled */
-	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0UL);
 
 	/* Ensure GPC are already enabled */
-	if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0U) {
+	if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0UL) {
 		ERROR("GPT: Granule protection checks are not enabled!\n");
 		return -EPERM;
 	}
@@ -1334,17 +1294,43 @@
 	gpt_l1_index_mask = GPT_L1_IDX_MASK(gpt_config.p);
 
 #if (RME_GPT_BITLOCK_BLOCK != 0)
-	/* Bitlocks at the end of L0 table */
-	gpt_bitlock_base = (bitlock_t *)(gpt_config.plat_gpt_l0_base +
-					GPT_L0_TABLE_SIZE(gpt_config.t));
-#endif
+	/*
+	 * Size of GPT bitlocks in bytes for the protected address space
+	 * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
+	 */
+	locks_size = GPT_PPS_ACTUAL_SIZE(gpt_config.t) /
+			(RME_GPT_BITLOCK_BLOCK * SZ_512M * 8U);
+	/*
+	 * If protected space size is less than the size covered
+	 * by 'bitlock' structure, check for a single bitlock.
+	 */
+	if (locks_size < LOCK_SIZE) {
+		locks_size = LOCK_SIZE;
+	/* Check bitlocks array size */
+	} else if (locks_size > l1_bitlocks_size) {
+		ERROR("GPT: Inadequate GPT bitlocks memory\n");
+		ERROR("      Expected 0x%lx bytes, got 0x%lx\n",
+			locks_size, l1_bitlocks_size);
+		return -ENOMEM;
+	}
+
+	gpt_bitlock = (bitlock_t *)l1_bitlocks_base;
+
+	/* Initialise GPT bitlocks */
+	(void)memset((void *)gpt_bitlock, 0, locks_size);
+
+	/* Flush GPT bitlocks to memory */
+	flush_dcache_range((uintptr_t)gpt_bitlock, locks_size);
+#endif /* RME_GPT_BITLOCK_BLOCK */
+
 	VERBOSE("GPT: Runtime Configuration\n");
 	VERBOSE("  PPS/T:     0x%x/%u\n", gpt_config.pps, gpt_config.t);
 	VERBOSE("  PGS/P:     0x%x/%u\n", gpt_config.pgs, gpt_config.p);
 	VERBOSE("  L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
 	VERBOSE("  L0 base:   0x%"PRIxPTR"\n", gpt_config.plat_gpt_l0_base);
 #if (RME_GPT_BITLOCK_BLOCK != 0)
-	VERBOSE("  Bitlocks:  0x%"PRIxPTR"\n", (uintptr_t)gpt_bitlock_base);
+	VERBOSE("  Bitlocks:  0x%"PRIxPTR"/0x%lx\n", (uintptr_t)gpt_bitlock,
+					locks_size);
 #endif
 	return 0;
 }
@@ -1391,7 +1377,7 @@
 	block_idx = (unsigned int)(base / (RME_GPT_BITLOCK_BLOCK * SZ_512M));
 
 	/* Bitlock address and mask */
-	gpi_info->lock = &gpt_bitlock_base[block_idx / LOCK_BITS];
+	gpi_info->lock = &gpt_bitlock[block_idx / LOCK_BITS];
 	gpi_info->mask = 1U << (block_idx & (LOCK_BITS - 1U));
 #endif
 	return 0;
diff --git a/lib/gpt_rme/gpt_rme.mk b/lib/gpt_rme/gpt_rme.mk
index 7d6b61f..6878489 100644
--- a/lib/gpt_rme/gpt_rme.mk
+++ b/lib/gpt_rme/gpt_rme.mk
@@ -1,19 +1,24 @@
 #
-# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+# RME_GPT_BITLOCK_BLOCK is the number of 512MB blocks
+# per bit and the value must be power of 2.
+BITLOCK_BLOCK_POWER_2=$(shell echo $$(( ${RME_GPT_BITLOCK_BLOCK} & (${RME_GPT_BITLOCK_BLOCK} - 1) )))
+
 # Process RME_GPT_BITLOCK_BLOCK value
-ifeq ($(filter 0 1 2 4 8 16 32 64 128 256 512, ${RME_GPT_BITLOCK_BLOCK}),)
-    $(error "Invalid value for RME_GPT_BITLOCK_BLOCK: ${RME_GPT_BITLOCK_BLOCK}")
+ifneq (${BITLOCK_BLOCK_POWER_2}, 0)
+    $(error "RME_GPT_BITLOCK_BLOCK must be power of 2. Invalid value ${RME_GPT_BITLOCK_BLOCK}.")
 endif
 
 ifeq (${RME_GPT_BITLOCK_BLOCK},0)
-    $(warning "GPT library uses global spinlock")
+    $(info "GPT library uses global spinlock")
 endif
 
-# Process RME_GPT_MAX_BLOCK value
+# Process the maximum size of supported contiguous blocks
+# RME_GPT_MAX_BLOCK
 ifeq ($(filter 0 2 32 512, ${RME_GPT_MAX_BLOCK}),)
     $(error "Invalid value for RME_GPT_MAX_BLOCK: ${RME_GPT_MAX_BLOCK}")
 endif
diff --git a/lib/gpt_rme/gpt_rme_private.h b/lib/gpt_rme/gpt_rme_private.h
index 31dad20..78d1cec 100644
--- a/lib/gpt_rme/gpt_rme_private.h
+++ b/lib/gpt_rme/gpt_rme_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,9 +7,7 @@
 #ifndef GPT_RME_PRIVATE_H
 #define GPT_RME_PRIVATE_H
 
-#include <arch.h>
 #include <lib/gpt_rme/gpt_rme.h>
-#include <lib/spinlock.h>
 #include <lib/utils_def.h>
 
 /******************************************************************************/
@@ -141,10 +139,6 @@
 	PGS_64KB_P =	16U
 } gpt_p_val_e;
 
-#define LOCK_SIZE	sizeof(((bitlock_t *)NULL)->lock)
-#define LOCK_TYPE	typeof(((bitlock_t *)NULL)->lock)
-#define LOCK_BITS	(LOCK_SIZE * 8U)
-
 /*
  * Internal structure to retrieve the values from get_gpi_params();
  */
diff --git a/lib/libc/libc_common.mk b/lib/libc/libc_common.mk
index 4879818..5f44bd5 100644
--- a/lib/libc/libc_common.mk
+++ b/lib/libc/libc_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -17,6 +17,7 @@
 			printf.c			\
 			putchar.c			\
 			puts.c				\
+			qsort.c				\
 			snprintf.c			\
 			strchr.c			\
 			strcmp.c			\
diff --git a/lib/libc/qsort.c b/lib/libc/qsort.c
new file mode 100644
index 0000000..40569f4
--- /dev/null
+++ b/lib/libc/qsort.c
@@ -0,0 +1,261 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(I_AM_QSORT_R)
+typedef int		 cmp_t(const void *, const void *, void *);
+#elif defined(I_AM_QSORT_R_COMPAT)
+typedef int		 cmp_t(void *, const void *, const void *);
+#elif defined(I_AM_QSORT_S)
+typedef int		 cmp_t(const void *, const void *, void *);
+#else
+typedef int		 cmp_t(const void *, const void *);
+#endif
+static inline char	*med3(char *, char *, char *, cmp_t *, void *);
+
+#define	MIN(a, b)	((a) < (b) ? a : b)
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+
+static inline void
+swapfunc(char *a, char *b, size_t es)
+{
+	char t;
+
+	do {
+		t = *a;
+		*a++ = *b;
+		*b++ = t;
+	} while (--es > 0);
+}
+
+#define	vecswap(a, b, n)				\
+	if ((n) > 0) swapfunc(a, b, n)
+
+#if defined(I_AM_QSORT_R)
+#define	CMP(t, x, y) (cmp((x), (y), (t)))
+#elif defined(I_AM_QSORT_R_COMPAT)
+#define	CMP(t, x, y) (cmp((t), (x), (y)))
+#elif defined(I_AM_QSORT_S)
+#define	CMP(t, x, y) (cmp((x), (y), (t)))
+#else
+#define	CMP(t, x, y) (cmp((x), (y)))
+#endif
+
+static inline char *
+med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
+#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_R_COMPAT) && !defined(I_AM_QSORT_S)
+__unused
+#endif
+)
+{
+	return CMP(thunk, a, b) < 0 ?
+	       (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
+	      :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
+}
+
+/*
+ * The actual qsort() implementation is static to avoid preemptible calls when
+ * recursing. Also give them different names for improved debugging.
+ */
+#if defined(I_AM_QSORT_R)
+#define local_qsort local_qsort_r
+#elif defined(I_AM_QSORT_R_COMPAT)
+#define local_qsort local_qsort_r_compat
+#elif defined(I_AM_QSORT_S)
+#define local_qsort local_qsort_s
+#endif
+static void
+local_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
+{
+	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+	size_t d1, d2;
+	int cmp_result;
+	int swap_cnt;
+
+	/* if there are less than 2 elements, then sorting is not needed */
+	if (__predict_false(n < 2))
+		return;
+loop:
+	swap_cnt = 0;
+	if (n < 7) {
+		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+			for (pl = pm;
+			     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+			     pl -= es)
+				swapfunc(pl, pl - es, es);
+		return;
+	}
+	pm = (char *)a + (n / 2) * es;
+	if (n > 7) {
+		pl = a;
+		pn = (char *)a + (n - 1) * es;
+		if (n > 40) {
+			size_t d = (n / 8) * es;
+
+			pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
+			pm = med3(pm - d, pm, pm + d, cmp, thunk);
+			pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
+		}
+		pm = med3(pl, pm, pn, cmp, thunk);
+	}
+	swapfunc(a, pm, es);
+	pa = pb = (char *)a + es;
+
+	pc = pd = (char *)a + (n - 1) * es;
+	for (;;) {
+		while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
+			if (cmp_result == 0) {
+				swap_cnt = 1;
+				swapfunc(pa, pb, es);
+				pa += es;
+			}
+			pb += es;
+		}
+		while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
+			if (cmp_result == 0) {
+				swap_cnt = 1;
+				swapfunc(pc, pd, es);
+				pd -= es;
+			}
+			pc -= es;
+		}
+		if (pb > pc)
+			break;
+		swapfunc(pb, pc, es);
+		swap_cnt = 1;
+		pb += es;
+		pc -= es;
+	}
+	if (swap_cnt == 0) {  /* Switch to insertion sort */
+		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
+			for (pl = pm;
+			     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
+			     pl -= es)
+				swapfunc(pl, pl - es, es);
+		return;
+	}
+
+	pn = (char *)a + n * es;
+	d1 = MIN(pa - (char *)a, pb - pa);
+	vecswap(a, pb - d1, d1);
+	/*
+	 * Cast es to preserve signedness of right-hand side of MIN()
+	 * expression, to avoid sign ambiguity in the implied comparison.  es
+	 * is safely within [0, SSIZE_MAX].
+	 */
+	d1 = MIN(pd - pc, pn - pd - (ssize_t)es);
+	vecswap(pb, pn - d1, d1);
+
+	d1 = pb - pa;
+	d2 = pd - pc;
+	if (d1 <= d2) {
+		/* Recurse on left partition, then iterate on right partition */
+		if (d1 > es) {
+			local_qsort(a, d1 / es, es, cmp, thunk);
+		}
+		if (d2 > es) {
+			/* Iterate rather than recurse to save stack space */
+			/* qsort(pn - d2, d2 / es, es, cmp); */
+			a = pn - d2;
+			n = d2 / es;
+			goto loop;
+		}
+	} else {
+		/* Recurse on right partition, then iterate on left partition */
+		if (d2 > es) {
+			local_qsort(pn - d2, d2 / es, es, cmp, thunk);
+		}
+		if (d1 > es) {
+			/* Iterate rather than recurse to save stack space */
+			/* qsort(a, d1 / es, es, cmp); */
+			n = d1 / es;
+			goto loop;
+		}
+	}
+}
+
+#if defined(I_AM_QSORT_R)
+void
+(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
+{
+	local_qsort_r(a, n, es, cmp, thunk);
+}
+#elif defined(I_AM_QSORT_R_COMPAT)
+void
+__qsort_r_compat(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
+{
+	local_qsort_r_compat(a, n, es, cmp, thunk);
+}
+#elif defined(I_AM_QSORT_S)
+errno_t
+qsort_s(void *a, rsize_t n, rsize_t es, cmp_t *cmp, void *thunk)
+{
+	if (n > RSIZE_MAX) {
+		__throw_constraint_handler_s("qsort_s : n > RSIZE_MAX", EINVAL);
+		return (EINVAL);
+	} else if (es > RSIZE_MAX) {
+		__throw_constraint_handler_s("qsort_s : es > RSIZE_MAX",
+		    EINVAL);
+		return (EINVAL);
+	} else if (n != 0) {
+		if (a == NULL) {
+			__throw_constraint_handler_s("qsort_s : a == NULL",
+			    EINVAL);
+			return (EINVAL);
+		} else if (cmp == NULL) {
+			__throw_constraint_handler_s("qsort_s : cmp == NULL",
+			    EINVAL);
+			return (EINVAL);
+		} else if (es <= 0) {
+			__throw_constraint_handler_s("qsort_s : es <= 0",
+			    EINVAL);
+			return (EINVAL);
+		}
+	}
+
+	local_qsort_s(a, n, es, cmp, thunk);
+	return (0);
+}
+#else
+void
+qsort(void *a, size_t n, size_t es, cmp_t *cmp)
+{
+	local_qsort(a, n, es, cmp, NULL);
+}
+#endif
diff --git a/lib/mpmm/mpmm.c b/lib/mpmm/mpmm.c
deleted file mode 100644
index dc61cf6..0000000
--- a/lib/mpmm/mpmm.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stdbool.h>
-
-#include <common/debug.h>
-#include <lib/mpmm/mpmm.h>
-
-#include <plat/common/platform.h>
-
-#if ENABLE_MPMM_FCONF
-#	include <lib/fconf/fconf.h>
-#	include <lib/fconf/fconf_mpmm_getter.h>
-#endif
-
-static uint64_t read_cpuppmcr_el3_mpmmpinctl(void)
-{
-	return (read_cpuppmcr_el3() >> CPUPPMCR_EL3_MPMMPINCTL_SHIFT) &
-		CPUPPMCR_EL3_MPMMPINCTL_MASK;
-}
-
-static void write_cpumpmmcr_el3_mpmm_en(uint64_t mpmm_en)
-{
-	uint64_t value = read_cpumpmmcr_el3();
-
-	value &= ~(CPUMPMMCR_EL3_MPMM_EN_MASK << CPUMPMMCR_EL3_MPMM_EN_SHIFT);
-	value |= (mpmm_en & CPUMPMMCR_EL3_MPMM_EN_MASK) <<
-		CPUMPMMCR_EL3_MPMM_EN_SHIFT;
-
-	write_cpumpmmcr_el3(value);
-}
-
-static bool mpmm_supported(void)
-{
-	bool supported = false;
-	const struct mpmm_topology *topology;
-
-#if ENABLE_MPMM_FCONF
-	topology = FCONF_GET_PROPERTY(mpmm, config, topology);
-#else
-	topology = plat_mpmm_topology();
-#endif /* ENABLE_MPMM_FCONF */
-
-	/*
-	 * For the current core firstly try to find out if the platform
-	 * configuration has claimed support for MPMM, then make sure that MPMM
-	 * is controllable through the system registers.
-	 */
-
-	if (topology != NULL) {
-		unsigned int core_pos = plat_my_core_pos();
-
-		supported = topology->cores[core_pos].supported &&
-			(read_cpuppmcr_el3_mpmmpinctl() == 0U);
-	} else {
-		ERROR("MPMM: failed to generate MPMM topology\n");
-	}
-
-	return supported;
-}
-
-/* Defaults to false */
-static bool mpmm_disable_for_errata;
-
-void mpmm_enable(void)
-{
-	if (mpmm_supported()) {
-		if (mpmm_disable_for_errata) {
-			WARN("MPMM: disabled by errata workaround\n");
-			return;
-		}
-		write_cpumpmmcr_el3_mpmm_en(1U);
-	}
-}
-
-/*
- * This function is called from assembly code very early in BL31 so it must be
- * small and simple.
- */
-void mpmm_errata_disable(void)
-{
-	mpmm_disable_for_errata = true;
-}
diff --git a/lib/mpmm/mpmm.mk b/lib/mpmm/mpmm.mk
deleted file mode 100644
index 826f925..0000000
--- a/lib/mpmm/mpmm.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (c) 2021, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-
-include lib/extensions/amu/amu.mk
-include lib/fconf/fconf.mk
-
-ifneq (${ENABLE_MPMM},0)
-        ifneq ($(ARCH),aarch64)
-                $(error MPMM support (`ENABLE_MPMM`) can only be enabled in AArch64 images (`ARCH`))
-        endif
-
-        ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0) # For MPMM gear AMU counters
-                $(error MPMM support (`ENABLE_MPM`) requires auxiliary AMU counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`))
-        endif
-endif
-
-MPMM_SOURCES	:=	lib/mpmm/mpmm.c
-MPMM_SOURCES	+=	${AMU_SOURCES}
-
-ifneq (${ENABLE_MPMM_FCONF},0)
-        ifeq (${ENABLE_MPMM},0)
-                $(error MPMM FCONF support (`ENABLE_MPMM_FCONF`) requires MPMM support (`ENABLE_MPMM`))
-        endif
-
-        MPMM_SOURCES	+= ${FCONF_MPMM_SOURCES}
-endif
diff --git a/lib/psci/aarch64/psci_helpers.S b/lib/psci/aarch64/psci_helpers.S
index cca08c1..b297f9b 100644
--- a/lib/psci/aarch64/psci_helpers.S
+++ b/lib/psci/aarch64/psci_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -118,17 +118,24 @@
 endfunc psci_do_pwrup_cache_maintenance
 
 /* -----------------------------------------------------------------------
- * void psci_power_down_wfi(void);
- * This function is called to indicate to the power controller that it
- * is safe to power down this cpu. It should not exit the wfi and will
- * be released from reset upon power up.
+ * void psci_power_down_wfi(void); This function is called to indicate to the
+ * power controller that it is safe to power down this cpu. It may exit if the
+ * request was denied and reset did not occur
  * -----------------------------------------------------------------------
  */
 func psci_power_down_wfi
 	apply_erratum cortex_a510, ERRATUM(2684597), ERRATA_A510_2684597
 
 	dsb	sy		// ensure write buffer empty
-1:
 	wfi
-	b	1b
+
+	/*
+	 * in case the WFI wasn't terminal, we have to undo errata mitigations.
+	 * These will be smart enough to handle being called the same way
+	 */
+	apply_erratum cortex_a710, ERRATUM(2291219), ERRATA_A710_2291219
+	apply_erratum cortex_x3,   ERRATUM(2313909), ERRATA_X3_2313909, NO_GET_CPU_REV
+	apply_erratum neoverse_n2, ERRATUM(2326639), ERRATA_N2_2326639, NO_GET_CPU_REV
+
+	ret
 endfunc psci_power_down_wfi
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 93d71b8..4c2601e 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -972,7 +972,7 @@
 	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
 
 	/* Init registers that never change for the lifetime of TF-A */
-	cm_manage_extensions_el3();
+	cm_manage_extensions_el3(cpu_idx);
 
 	/*
 	 * Verify that we have been explicitly turned ON or resumed from
@@ -1019,8 +1019,12 @@
 	 */
 	if (psci_get_aff_info_state() == AFF_STATE_ON_PENDING)
 		psci_cpu_on_finish(cpu_idx, &state_info);
-	else
-		psci_cpu_suspend_to_powerdown_finish(cpu_idx, &state_info);
+	else {
+		unsigned int max_off_lvl = psci_find_max_off_lvl(&state_info);
+
+		assert(max_off_lvl != PSCI_INVALID_PWR_LVL);
+		psci_cpu_suspend_to_powerdown_finish(cpu_idx, max_off_lvl, &state_info);
+	}
 
 	/*
 	 * Generic management: Now we just need to retrieve the
@@ -1156,7 +1160,7 @@
  * Initiate power down sequence, by calling power down operations registered for
  * this CPU.
  ******************************************************************************/
-void psci_pwrdown_cpu(unsigned int power_level)
+void psci_pwrdown_cpu_start(unsigned int power_level)
 {
 #if ENABLE_RUNTIME_INSTRUMENTATION
 
@@ -1197,6 +1201,72 @@
 }
 
 /*******************************************************************************
+ * Finish a terminal power down sequence, ending with a wfi. In case of wakeup
+ * will retry the sleep and panic if it persists.
+ ******************************************************************************/
+void __dead2 psci_pwrdown_cpu_end_terminal(void)
+{
+#if ERRATA_SME_POWER_DOWN
+	/*
+	 * force SME off to not get power down rejected. Getting here is
+	 * terminal so we don't care if we lose context because of another
+	 * wakeup
+	 */
+	if (is_feat_sme_supported()) {
+		write_svcr(0);
+		isb();
+	}
+#endif /* ERRATA_SME_POWER_DOWN */
+
+	/*
+	 * Execute a wfi which, in most cases, will allow the power controller
+	 * to physically power down this cpu. Under some circumstances that may
+	 * be denied. Hopefully this is transient, retrying a few times should
+	 * power down.
+	 */
+	for (int i = 0; i < 32; i++)
+		psci_power_down_wfi();
+
+	/* Wake up wasn't transient. System is probably in a bad state. */
+	ERROR("Could not power off CPU.\n");
+	panic();
+}
+
+/*******************************************************************************
+ * Finish a non-terminal power down sequence, ending with a wfi. In case of
+ * wakeup will unwind any CPU specific actions and return.
+ ******************************************************************************/
+
+void psci_pwrdown_cpu_end_wakeup(unsigned int power_level)
+{
+	/*
+	 * Usually, will be terminal. In some circumstances the powerdown will
+	 * be denied and we'll need to unwind
+	 */
+	psci_power_down_wfi();
+
+	/*
+	 * Waking up does not require hardware-assisted coherency, but that is
+	 * the case for every core that can wake up. Untangling the cache
+	 * coherency code from powerdown is a non-trivial effort which isn't
+	 * needed for our purposes.
+	 */
+#if !FEAT_PABANDON
+	ERROR("Systems without FEAT_PABANDON shouldn't wake up.\n");
+	panic();
+#else /* FEAT_PABANDON */
+
+	/*
+	 * Begin unwinding. Everything can be shared with CPU_ON and co later,
+	 * except the CPU specific bit. Cores that have hardware-assisted
+	 * coherency don't have much to do so just calling the hook again is
+	 * the simplest way to achieve this
+	 */
+	prepare_cpu_pwr_dwn(power_level);
+#endif /* FEAT_PABANDON */
+}
+
+/*******************************************************************************
  * This function invokes the callback 'stop_func()' with the 'mpidr' of each
  * online PE. Caller can pass suitable method to stop a remote core.
  *
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 7ac0e02..45be63a 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <lib/pmf/pmf.h>
@@ -64,6 +65,19 @@
 	plat_local_state_t prev[PLAT_MAX_PWR_LVL];
 #endif
 
+#if ERRATA_SME_POWER_DOWN
+	/*
+	 * If SME isn't off, attempting a real power down will only end up being
+	 * rejected. If we got called with SME on, fall back to a normal
+	 * suspend. We can't force SME off as in the event the power down is
+	 * rejected for another reason (eg GIC) we'd lose the SME context.
+	 */
+	if (is_feat_sme_supported() && read_svcr() != 0) {
+		power_state &= ~(PSTATE_TYPE_MASK << PSTATE_TYPE_SHIFT);
+		power_state &= ~(PSTATE_PWR_LVL_MASK << PSTATE_PWR_LVL_SHIFT);
+	}
+#endif /* ERRATA_SME_POWER_DOWN */
+
 	/* Validate the power_state parameter */
 	rc = psci_validate_power_state(power_state, &state_info);
 	if (rc != PSCI_E_SUCCESS) {
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
index d40ee3f..577fdd7 100644
--- a/lib/psci/psci_off.c
+++ b/lib/psci/psci_off.c
@@ -93,7 +93,7 @@
 	 */
 	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_off != NULL)) {
 		rc = psci_spd_pm->svc_off(0);
-		if (rc != 0)
+		if (rc != PSCI_E_SUCCESS)
 			goto exit;
 	}
 
@@ -115,7 +115,7 @@
 	/*
 	 * Arch. management. Initiate power down sequence.
 	 */
-	psci_pwrdown_cpu(psci_find_max_off_lvl(&state_info));
+	psci_pwrdown_cpu_start(psci_find_max_off_lvl(&state_info));
 
 	/*
 	 * Plat. management: Perform platform specific actions to turn this
@@ -153,7 +153,6 @@
 		psci_inv_cpu_data(psci_svc_cpu_data.aff_info_state);
 
 #if ENABLE_RUNTIME_INSTRUMENTATION
-
 		/*
 		 * Update the timestamp with cache off.  We assume this
 		 * timestamp can only be read from the current CPU and the
@@ -164,17 +163,12 @@
 		    RT_INSTR_ENTER_HW_LOW_PWR,
 		    PMF_NO_CACHE_MAINT);
 #endif
-
-		if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL) {
-			/* This function must not return */
-			psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info);
-		} else {
-			/*
-			 * Enter a wfi loop which will allow the power
-			 * controller to physically power down this cpu.
-			 */
-			psci_power_down_wfi();
+		if (psci_plat_pm_ops->pwr_domain_pwr_down != NULL) {
+			/* This function may not return */
+			psci_plat_pm_ops->pwr_domain_pwr_down(&state_info);
 		}
+
+		psci_pwrdown_cpu_end_terminal();
 	}
 
 	return rc;
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index 6622755..49b19c9 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -349,7 +349,7 @@
 			   psci_power_state_t *state_info,
 			   unsigned int is_power_down_state);
 
-void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power_state_t *state_info);
+void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, unsigned int max_off_lvl, const psci_power_state_t *state_info);
 
 /* Private exported functions from psci_helpers.S */
 void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level);
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
index 2aadbfd..0fb1ed3 100644
--- a/lib/psci/psci_suspend.c
+++ b/lib/psci/psci_suspend.c
@@ -25,8 +25,7 @@
  * This function does generic and platform specific operations after a wake-up
  * from standby/retention states at multiple power levels.
  ******************************************************************************/
-static void psci_cpu_suspend_to_standby_finish(unsigned int cpu_idx,
-					     unsigned int end_pwrlvl,
+static void psci_cpu_suspend_to_standby_finish(unsigned int end_pwrlvl,
 					     psci_power_state_t *state_info)
 {
 	/*
@@ -43,13 +42,13 @@
  * This function does generic and platform specific suspend to power down
  * operations.
  ******************************************************************************/
-static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl,
+static void psci_suspend_to_pwrdown_start(unsigned int idx,
+					  unsigned int end_pwrlvl,
+					  unsigned int max_off_lvl,
 					  const entry_point_info_t *ep,
 					  const psci_power_state_t *state_info)
 {
-	unsigned int max_off_lvl = psci_find_max_off_lvl(state_info);
-
-	PUBLISH_EVENT(psci_suspend_pwrdown_start);
+	PUBLISH_EVENT_ARG(psci_suspend_pwrdown_start, &idx);
 
 #if PSCI_OS_INIT_MODE
 #ifdef PLAT_MAX_CPU_SUSPEND_PWR_LVL
@@ -94,10 +93,8 @@
 
 	/*
 	 * Arch. management. Initiate power down sequence.
-	 * TODO : Introduce a mechanism to query the cache level to flush
-	 * and the cpu-ops power down to perform from the platform.
 	 */
-	psci_pwrdown_cpu(max_off_lvl);
+	psci_pwrdown_cpu_start(max_off_lvl);
 }
 
 /*******************************************************************************
@@ -125,8 +122,12 @@
 			   unsigned int is_power_down_state)
 {
 	int rc = PSCI_E_SUCCESS;
-	bool skip_wfi = false;
 	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+	unsigned int max_off_lvl = 0;
+#if FEAT_PABANDON
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	cpu_context_t old_ctx;
+#endif
 
 	/*
 	 * This function must only be called on platforms where the
@@ -151,7 +152,6 @@
 	 * detection that a wake-up interrupt has fired.
 	 */
 	if (read_isr_el1() != 0U) {
-		skip_wfi = true;
 		goto exit;
 	}
 
@@ -163,7 +163,6 @@
 		 */
 		rc = psci_validate_state_coordination(idx, end_pwrlvl, state_info);
 		if (rc != PSCI_E_SUCCESS) {
-			skip_wfi = true;
 			goto exit;
 		}
 	} else {
@@ -182,7 +181,6 @@
 	if (psci_plat_pm_ops->pwr_domain_validate_suspend != NULL) {
 		rc = psci_plat_pm_ops->pwr_domain_validate_suspend(state_info);
 		if (rc != PSCI_E_SUCCESS) {
-			skip_wfi = true;
 			goto exit;
 		}
 	}
@@ -196,8 +194,38 @@
 	psci_stats_update_pwr_down(idx, end_pwrlvl, state_info);
 #endif
 
-	if (is_power_down_state != 0U)
-		psci_suspend_to_pwrdown_start(end_pwrlvl, ep, state_info);
+	if (is_power_down_state != 0U) {
+		/*
+		 * WHen CTX_INCLUDE_EL2_REGS is usnet, we're probably runnig
+		 * with some SPD that assumes the core is going off so it
+		 * doesn't bother saving NS's context. Do that here until we
+		 * figure out a way to make this coherent.
+		 */
+#if FEAT_PABANDON
+#if !CTX_INCLUDE_EL2_REGS
+		cm_el1_sysregs_context_save(NON_SECURE);
+#endif
+		/*
+		 * when the core wakes it expects its context to already be in
+		 * place so we must overwrite it before powerdown. But if
+		 * powerdown never happens we want the old context. Save it in
+		 * case we wake up. EL2/El1 will not be touched by PSCI so don't
+		 * copy */
+		memcpy(&ctx->gpregs_ctx, &old_ctx.gpregs_ctx, sizeof(gp_regs_t));
+		memcpy(&ctx->el3state_ctx, &old_ctx.el3state_ctx, sizeof(el3_state_t));
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+		memcpy(&ctx->cve_2018_3639_ctx, &old_ctx.cve_2018_3639_ctx, sizeof(cve_2018_3639_t));
+#endif
+#if ERRATA_SPECULATIVE_AT
+		memcpy(&ctx->errata_speculative_at_ctx, &old_ctx.errata_speculative_at_ctx, sizeof(errata_speculative_at_t));
+#endif
+#if CTX_INCLUDE_PAUTH_REGS
+		memcpy(&ctx->pauth_ctx, &old_ctx.pauth_ctx, sizeof(pauth_t));
+#endif
+#endif
+		max_off_lvl = psci_find_max_off_lvl(state_info);
+		psci_suspend_to_pwrdown_start(idx, end_pwrlvl, end_pwrlvl, ep, state_info);
+	}
 
 	/*
 	 * Plat. management: Allow the platform to perform the
@@ -212,50 +240,39 @@
 	plat_psci_stat_accounting_start(state_info);
 #endif
 
-exit:
 	/*
 	 * Release the locks corresponding to each power level in the
 	 * reverse order to which they were acquired.
 	 */
 	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
 
-	if (skip_wfi) {
-		return rc;
-	}
-
-	if (is_power_down_state != 0U) {
 #if ENABLE_RUNTIME_INSTRUMENTATION
-
-		/*
-		 * Update the timestamp with cache off.  We assume this
-		 * timestamp can only be read from the current CPU and the
-		 * timestamp cache line will be flushed before return to
-		 * normal world on wakeup.
-		 */
-		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
-		    RT_INSTR_ENTER_HW_LOW_PWR,
-		    PMF_NO_CACHE_MAINT);
-#endif
-
-		/* The function calls below must not return */
-		if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL)
-			psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info);
-		else
-			psci_power_down_wfi();
-	}
-
-#if ENABLE_RUNTIME_INSTRUMENTATION
+	/*
+	 * Update the timestamp with cache off. We assume this
+	 * timestamp can only be read from the current CPU and the
+	 * timestamp cache line will be flushed before return to
+	 * normal world on wakeup.
+	 */
 	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
 	    RT_INSTR_ENTER_HW_LOW_PWR,
 	    PMF_NO_CACHE_MAINT);
 #endif
 
-	/*
-	 * We will reach here if only retention/standby states have been
-	 * requested at multiple power levels. This means that the cpu
-	 * context will be preserved.
-	 */
-	wfi();
+	if (is_power_down_state != 0U) {
+		if (psci_plat_pm_ops->pwr_domain_pwr_down != NULL) {
+			/* This function may not return */
+			psci_plat_pm_ops->pwr_domain_pwr_down(state_info);
+		}
+
+		psci_pwrdown_cpu_end_wakeup(max_off_lvl);
+	} else {
+		/*
+		 * We will reach here if only retention/standby states have been
+		 * requested at multiple power levels. This means that the cpu
+		 * context will be preserved.
+		 */
+		wfi();
+	}
 
 #if ENABLE_RUNTIME_INSTRUMENTATION
 	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
@@ -277,10 +294,32 @@
 #endif
 
 	/*
-	 * After we wake up from context retaining suspend, call the
-	 * context retaining suspend finisher.
+	 * Waking up means we've retained all context. Call the finishers to put
+	 * the system back to a usable state.
 	 */
-	psci_cpu_suspend_to_standby_finish(idx, end_pwrlvl, state_info);
+	if (is_power_down_state != 0U) {
+#if FEAT_PABANDON
+		psci_cpu_suspend_to_powerdown_finish(idx, max_off_lvl, state_info);
+
+		/* we overwrote context ourselves, put it back */
+		memcpy(&ctx->gpregs_ctx, &old_ctx.gpregs_ctx, sizeof(gp_regs_t));
+		memcpy(&ctx->el3state_ctx, &old_ctx.el3state_ctx, sizeof(el3_state_t));
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+		memcpy(&ctx->cve_2018_3639_ctx, &old_ctx.cve_2018_3639_ctx, sizeof(cve_2018_3639_t));
+#endif
+#if ERRATA_SPECULATIVE_AT
+		memcpy(&ctx->errata_speculative_at_ctx, &old_ctx.errata_speculative_at_ctx, sizeof(errata_speculative_at_t));
+#endif
+#if CTX_INCLUDE_PAUTH_REGS
+		memcpy(&ctx->pauth_ctx, &old_ctx.pauth_ctx, sizeof(pauth_t));
+#endif
+#if !CTX_INCLUDE_EL2_REGS
+		cm_el1_sysregs_context_restore(NON_SECURE);
+#endif
+#endif
+	} else {
+		psci_cpu_suspend_to_standby_finish(end_pwrlvl, state_info);
+	}
 
 	/*
 	 * Set the requested and target state of this CPU and all the higher
@@ -288,6 +327,7 @@
 	 */
 	psci_set_pwr_domains_to_run(idx, end_pwrlvl);
 
+exit:
 	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
 
 	return rc;
@@ -298,10 +338,9 @@
  * are called by the common finisher routine in psci_common.c. The `state_info`
  * is the psci_power_state from which this CPU has woken up from.
  ******************************************************************************/
-void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power_state_t *state_info)
+void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, unsigned int max_off_lvl, const psci_power_state_t *state_info)
 {
 	unsigned int counter_freq;
-	unsigned int max_off_lvl;
 
 	/* Ensure we have been woken up from a suspended state */
 	assert((psci_get_aff_info_state() == AFF_STATE_ON) &&
@@ -338,13 +377,11 @@
 	 * error, it's expected to assert within
 	 */
 	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend_finish != NULL)) {
-		max_off_lvl = psci_find_max_off_lvl(state_info);
-		assert(max_off_lvl != PSCI_INVALID_PWR_LVL);
 		psci_spd_pm->svc_suspend_finish(max_off_lvl);
 	}
 
 	/* This loses its meaning when not suspending, reset so it's correct for OFF */
 	psci_set_suspend_pwrlvl(PLAT_MAX_PWR_LVL);
 
-	PUBLISH_EVENT(psci_suspend_pwrdown_finish);
+	PUBLISH_EVENT_ARG(psci_suspend_pwrdown_finish, &cpu_idx);
 }
diff --git a/lib/psci/psci_system_off.c b/lib/psci/psci_system_off.c
index 002392c..b9418a3 100644
--- a/lib/psci/psci_system_off.c
+++ b/lib/psci/psci_system_off.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -30,7 +30,7 @@
 	/* Call the platform specific hook */
 	psci_plat_pm_ops->system_off();
 
-	/* This function does not return. We should never get here */
+	psci_pwrdown_cpu_end_terminal();
 }
 
 void __dead2 psci_system_reset(void)
@@ -49,7 +49,7 @@
 	/* Call the platform specific hook */
 	psci_plat_pm_ops->system_reset();
 
-	/* This function does not return. We should never get here */
+	psci_pwrdown_cpu_end_terminal();
 }
 
 u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie)
@@ -79,7 +79,10 @@
 	}
 	console_flush();
 
-	return (u_register_t)
-		psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type,
-						cookie);
+	u_register_t ret =
+		(u_register_t) psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type, cookie);
+	if (ret != PSCI_E_SUCCESS)
+		return ret;
+
+	psci_pwrdown_cpu_end_terminal();
 }
diff --git a/lib/romlib/Makefile b/lib/romlib/Makefile
index 01a0395..71f4273 100644
--- a/lib/romlib/Makefile
+++ b/lib/romlib/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -23,7 +23,14 @@
 # Determine if mbedtls is needed
 ifneq ($(filter $(CRYPTO_SUPPORT),1 2 3),)
     PROCESSED_JMPTBL = $(BUILD_DIR)/jmptbl_processed.i
-    $(shell mkdir -p $(BUILD_DIR) && cat ../../$(PLAT_DIR)/jmptbl.i ../../$(PLAT_DIR)/jmptbl_mbedtls.i > $(BUILD_DIR)/jmptbl_processed.i)
+    CRYPTO_JMPTBL = ../../$(PLAT_DIR)/jmptbl.i ../../$(PLAT_DIR)/jmptbl_mbedtls.i
+
+    ifeq (${PSA_CRYPTO},1)
+        CRYPTO_JMPTBL += ../../$(PLAT_DIR)/jmptbl_mbedtls_psa.i
+    endif # ifeq (${PSA_CRYPTO},1)
+
+    $(shell mkdir -p $(BUILD_DIR) && cat $(CRYPTO_JMPTBL) > $(PROCESSED_JMPTBL))
+
     LIBS += $(LIB_DIR)/libmbedtls.a
 endif
 
diff --git a/lib/transfer_list/transfer_list.c b/lib/transfer_list/transfer_list.c
index 07614a6..3817861 100644
--- a/lib/transfer_list/transfer_list.c
+++ b/lib/transfer_list/transfer_list.c
@@ -35,7 +35,15 @@
 		if (!te) {
 			break;
 		}
+
 		INFO("Entry %d:\n", i++);
+		transfer_entry_dump(te);
+	}
+}
+
+void transfer_entry_dump(struct transfer_list_entry *te)
+{
+	if (te) {
 		INFO("tag_id     0x%x\n", te->tag_id);
 		INFO("hdr_size   0x%x\n", te->hdr_size);
 		INFO("data_size  0x%x\n", te->data_size);
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
index 971dba4..bd7f017 100644
--- a/lib/xlat_tables_v2/xlat_tables_core.c
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,7 @@
 #include <arch_features.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
+#include <lib/utils.h>
 #include <lib/utils_def.h>
 #include <lib/xlat_tables/xlat_tables_defs.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
@@ -1204,16 +1205,13 @@
 	xlat_mmap_print(mm);
 
 	/* All tables must be zeroed before mapping any region. */
+	zeromem(ctx->base_table, ctx->base_table_entries * sizeof(uint64_t));
 
-	for (unsigned int i = 0U; i < ctx->base_table_entries; i++)
-		ctx->base_table[i] = INVALID_DESC;
-
-	for (int j = 0; j < ctx->tables_num; j++) {
 #if PLAT_XLAT_TABLES_DYNAMIC
-		ctx->tables_mapped_regions[j] = 0;
+	zeromem(ctx->tables_mapped_regions, ctx->tables_num * sizeof(uint32_t));
 #endif
-		for (unsigned int i = 0U; i < XLAT_TABLE_ENTRIES; i++)
-			ctx->tables[j][i] = INVALID_DESC;
+	for (int i = 0; i < ctx->tables_num; i++) {
+		zeromem(ctx->tables[i], XLAT_TABLE_ENTRIES * sizeof(uint64_t));
 	}
 
 	while (mm->size != 0U) {
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
index 3c9e136..8dec522 100644
--- a/make_helpers/arch_features.mk
+++ b/make_helpers/arch_features.mk
@@ -291,7 +291,6 @@
 # Feature flags for supporting Activity monitor extensions.
 ENABLE_FEAT_AMU				?=	0
 ENABLE_AMU_AUXILIARY_COUNTERS		?=	0
-ENABLE_AMU_FCONF			?=	0
 AMU_RESTRICT_COUNTERS			?=	1
 
 # Build option to enable MPAM for lower ELs.
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index b1b299c..aa16751 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -604,6 +604,7 @@
 $(DOBJ): $(DPRE) $(filter-out %.d,$(MAKEFILE_LIST)) | $$$$(@D)/
 	$$(s)echo "  DTC     $$<"
 	$$(q)$($(ARCH)-dtc) $$(DTC_FLAGS) -d $(DTBDEP) -o $$@ $$<
+	$$($$@-after)
 
 -include $(DTBDEP)
 -include $(DTSDEP)
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index b1cfda2..ec2aa1b 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -85,8 +85,8 @@
 # Enable the Maximum Power Mitigation Mechanism on supporting cores.
 ENABLE_MPMM			:= 0
 
-# Enable MPMM configuration via FCONF.
-ENABLE_MPMM_FCONF		:= 0
+# Enable support for powerdown abandons
+FEAT_PABANDON			:= 0
 
 # Flag to Enable Position Independant support (PIE)
 ENABLE_PIE			:= 0
@@ -348,6 +348,9 @@
 # Select workaround for AT speculative behaviour.
 ERRATA_SPECULATIVE_AT		:= 0
 
+# select workaround for SME aborting powerdown
+ERRATA_SME_POWER_DOWN		:= 0
+
 # Trap RAS error record access from Non secure
 RAS_TRAP_NS_ERR_REC_ACCESS	:= 0
 
diff --git a/plat/allwinner/common/sunxi_native_pm.c b/plat/allwinner/common/sunxi_native_pm.c
index 148f50e..558b0bb 100644
--- a/plat/allwinner/common/sunxi_native_pm.c
+++ b/plat/allwinner/common/sunxi_native_pm.c
@@ -49,6 +49,8 @@
 	sunxi_cpu_power_off_others();
 	sunxi_cpu_power_off_self();
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 static void __dead2 sunxi_system_reset(void)
diff --git a/plat/allwinner/common/sunxi_scpi_pm.c b/plat/allwinner/common/sunxi_scpi_pm.c
index 6a0e967..8870a71 100644
--- a/plat/allwinner/common/sunxi_scpi_pm.c
+++ b/plat/allwinner/common/sunxi_scpi_pm.c
@@ -108,6 +108,8 @@
 	}
 
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 static void __dead2 sunxi_system_reset(void)
@@ -123,6 +125,8 @@
 	}
 
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 static int sunxi_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
@@ -142,6 +146,8 @@
 	}
 
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 
 	/*
 	 * Should not reach here.
diff --git a/plat/xilinx/common/include/plat_xfer_list.h b/plat/amd/common/include/plat_xfer_list.h
similarity index 64%
rename from plat/xilinx/common/include/plat_xfer_list.h
rename to plat/amd/common/include/plat_xfer_list.h
index cc79a2c..24a9c0c 100644
--- a/plat/xilinx/common/include/plat_xfer_list.h
+++ b/plat/amd/common/include/plat_xfer_list.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2023-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,4 +12,7 @@
 int32_t transfer_list_populate_ep_info(entry_point_info_t *bl32,
 				       entry_point_info_t *bl33);
 
+void *transfer_list_retrieve_dt_address(void);
+bool populate_data_from_xfer_list(void);
+
 #endif /* PLAT_XFER_LIST_H */
diff --git a/plat/amd/common/plat_fdt.c b/plat/amd/common/plat_fdt.c
new file mode 100644
index 0000000..e72c0dd
--- /dev/null
+++ b/plat/amd/common/plat_fdt.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <platform_def.h>
+
+#include <plat_fdt.h>
+#include <plat_xfer_list.h>
+
+#define FIT_CONFS_PATH	"/configurations"
+
+static bool is_fit_image(void *dtb)
+{
+	int64_t confs_noffset = 0;
+	bool status = true;
+
+	confs_noffset = fdt_path_offset(dtb, FIT_CONFS_PATH);
+
+	/* confs_noffset is only present on FIT image */
+	if (confs_noffset < 0) {
+		status = false;
+	}
+
+	return status;
+}
+
+int32_t is_valid_dtb(void *fdt)
+{
+	int32_t ret = 0;
+
+	ret = fdt_check_header(fdt);
+	if (ret != 0) {
+		ERROR("Can't read DT at %p\n", fdt);
+		goto error;
+	}
+
+	ret = fdt_open_into(fdt, fdt, XILINX_OF_BOARD_DTB_MAX_SIZE);
+	if (ret < 0) {
+		ERROR("Invalid Device Tree at %p: error %d\n", fdt, ret);
+		goto error;
+	}
+
+	if (is_fit_image(fdt)) {
+		WARN("FIT image detected, TF-A will not update DTB for DDR address space\n");
+		ret = -FDT_ERR_NOTFOUND;
+	}
+error:
+	return ret;
+}
+
+/* TODO: Reserve TFA memory in DT through custom TL entry */
+void prepare_dtb(void)
+{
+
+}
+
+uintptr_t plat_retrieve_dt_addr(void)
+{
+	void *dtb = NULL;
+
+	dtb = transfer_list_retrieve_dt_address();
+	if (dtb == NULL) {
+		WARN("TL header or DT entry is invalid\n");
+	}
+
+	return (uintptr_t)dtb;
+}
diff --git a/plat/amd/common/plat_xfer_list.c b/plat/amd/common/plat_xfer_list.c
new file mode 100644
index 0000000..7af6726
--- /dev/null
+++ b/plat/amd/common/plat_xfer_list.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2023-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stddef.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/transfer_list.h>
+#include <platform_def.h>
+
+
+static struct transfer_list_header *tl_hdr;
+static int32_t tl_ops_holder;
+
+bool populate_data_from_xfer_list(void)
+{
+	bool ret = true;
+
+	tl_hdr = (struct transfer_list_header *)FW_HANDOFF_BASE;
+	tl_ops_holder = transfer_list_check_header(tl_hdr);
+
+	if ((tl_ops_holder != TL_OPS_ALL) && (tl_ops_holder != TL_OPS_RO)) {
+		ret = false;
+	}
+
+	return ret;
+}
+
+int32_t transfer_list_populate_ep_info(entry_point_info_t *bl32,
+				       entry_point_info_t *bl33)
+{
+	int32_t ret = tl_ops_holder;
+	struct transfer_list_entry *te = NULL;
+	struct entry_point_info *ep = NULL;
+
+	if ((tl_ops_holder == TL_OPS_ALL) || (tl_ops_holder == TL_OPS_RO)) {
+		transfer_list_dump(tl_hdr);
+		while ((te = transfer_list_next(tl_hdr, te)) != NULL) {
+			ep = transfer_list_entry_data(te);
+			if (te->tag_id == TL_TAG_EXEC_EP_INFO64) {
+				switch (GET_SECURITY_STATE(ep->h.attr)) {
+				case NON_SECURE:
+					*bl33 = *ep;
+					continue;
+				case SECURE:
+					*bl32 = *ep;
+					if (!transfer_list_set_handoff_args(tl_hdr, ep)) {
+						ERROR("Invalid transfer list\n");
+					}
+					continue;
+				default:
+					ERROR("Unrecognized Image Security State %lu\n",
+					      GET_SECURITY_STATE(ep->h.attr));
+					ret = TL_OPS_NON;
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+void *transfer_list_retrieve_dt_address(void)
+{
+	void *dtb = NULL;
+	struct transfer_list_entry *te = NULL;
+
+	if ((tl_ops_holder == TL_OPS_ALL) || (tl_ops_holder == TL_OPS_RO)) {
+		te = transfer_list_find(tl_hdr, TL_TAG_FDT);
+		if (te != NULL) {
+			dtb = transfer_list_entry_data(te);
+		}
+	}
+
+	return dtb;
+}
diff --git a/plat/amd/versal2/bl31_setup.c b/plat/amd/versal2/bl31_setup.c
index 1914830..3a856cb 100644
--- a/plat/amd/versal2/bl31_setup.c
+++ b/plat/amd/versal2/bl31_setup.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -59,9 +59,11 @@
 	bl32_image_ep_info.pc = BL32_BASE;
 	bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
 #if defined(SPD_opteed)
+#if (TRANSFER_LIST == 0)
 	/* NS dtb addr passed to optee_os */
 	bl32_image_ep_info.args.arg3 = XILINX_OF_BOARD_DTB_ADDR;
 #endif
+#endif
 	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
 	bl33_image_ep_info.spsr = (uint32_t)SPSR_64(MODE_EL2, MODE_SP_ELX,
 					  DISABLE_ALL_EXCEPTIONS);
@@ -81,7 +83,10 @@
 	(void)arg2;
 	(void)arg3;
 	uint32_t uart_clock;
+#if (TRANSFER_LIST == 1)
 	int32_t rc;
+	bool tl_status = false;
+#endif
 
 	board_detection();
 
@@ -124,6 +129,12 @@
 	default:
 		panic();
 	}
+#if (TRANSFER_LIST == 1)
+	tl_status = populate_data_from_xfer_list();
+	if (tl_status != true) {
+		WARN("Invalid transfer list\n");
+	}
+#endif
 
 	uart_clock = get_uart_clk();
 
@@ -152,11 +163,15 @@
 	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
 	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
 
+#if (TRANSFER_LIST == 1)
 	rc = transfer_list_populate_ep_info(&bl32_image_ep_info, &bl33_image_ep_info);
 	if (rc == TL_OPS_NON || rc == TL_OPS_CUS) {
 		NOTICE("BL31: TL not found, using default config\n");
 		bl31_set_default_config();
 	}
+#else
+	bl31_set_default_config();
+#endif
 
 	long rev_var = cpu_get_rev_var();
 
diff --git a/plat/amd/versal2/include/plat_pm_common.h b/plat/amd/versal2/include/plat_pm_common.h
index 5e68472..c325d74 100644
--- a/plat/amd/versal2/include/plat_pm_common.h
+++ b/plat/amd/versal2/include/plat_pm_common.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,4 +22,17 @@
 #define NON_SECURE_FLAG		1U
 #define SECURE_FLAG		0U
 
+/* Processor core device IDs */
+#define PM_DEV_CLUSTER0_ACPU_0	(0x1810C0AFU)
+#define PM_DEV_CLUSTER0_ACPU_1	(0x1810C0B0U)
+
+#define PM_DEV_CLUSTER1_ACPU_0	(0x1810C0B3U)
+#define PM_DEV_CLUSTER1_ACPU_1	(0x1810C0B4U)
+
+#define PM_DEV_CLUSTER2_ACPU_0	(0x1810C0B7U)
+#define PM_DEV_CLUSTER2_ACPU_1	(0x1810C0B8U)
+
+#define PM_DEV_CLUSTER3_ACPU_0	(0x1810C0BBU)
+#define PM_DEV_CLUSTER3_ACPU_1	(0x1810C0BCU)
+
 #endif /* PLAT_PM_COMMON_H */
diff --git a/plat/amd/versal2/include/plat_private.h b/plat/amd/versal2/include/plat_private.h
index 4be2061..98f7e08 100644
--- a/plat/amd/versal2/include/plat_private.h
+++ b/plat/amd/versal2/include/plat_private.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -45,7 +45,7 @@
 void board_detection(void);
 const char *board_name_decode(void);
 uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
-		       uint64_t x4, void *cookie, void *handle, uint64_t flags);
+		       uint64_t x4, const void *cookie, void *handle, uint64_t flags);
 int32_t sip_svc_setup_init(void);
 /*
  * Register handler to specific GIC entrance
diff --git a/plat/amd/versal2/include/platform_def.h b/plat/amd/versal2/include/platform_def.h
index 8f694f7..2b65363 100644
--- a/plat/amd/versal2/include/platform_def.h
+++ b/plat/amd/versal2/include/platform_def.h
@@ -11,6 +11,7 @@
 
 #include <arch.h>
 #include "def.h"
+#include <plat_common.h>
 
 /*******************************************************************************
  * Generic platform constants
@@ -122,6 +123,8 @@
 
 #define PLAT_GICD_BASE_VALUE	U(0xE2000000)
 #define PLAT_GICR_BASE_VALUE	U(0xE2060000)
+#define PLAT_ARM_GICR_BASE	PLAT_GICR_BASE_VALUE
+#define PLAT_ARM_GICD_BASE	PLAT_GICD_BASE_VALUE
 
 /*
  * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
@@ -138,6 +141,8 @@
 #define PLAT_G0_IRQ_PROPS(grp) \
 	INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \
 			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(CPU_PWR_DOWN_REQ_INTR, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
 
 #define IRQ_MAX		200U
 
diff --git a/plat/amd/versal2/plat_psci.c b/plat/amd/versal2/plat_psci.c
index 55842cc..d53d751 100644
--- a/plat/amd/versal2/plat_psci.c
+++ b/plat/amd/versal2/plat_psci.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -200,7 +200,7 @@
 }
 
 static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
-			      uint64_t x4, void *cookie, void *handle, uint64_t flags)
+			      uint64_t x4, const void *cookie, void *handle, uint64_t flags)
 {
 	int32_t ret;
 	uint32_t arg[4], api_id;
@@ -240,7 +240,7 @@
 }
 
 uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
-		     void *cookie, void *handle, uint64_t flags)
+		     const void *cookie, void *handle, uint64_t flags)
 {
 	return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
 }
diff --git a/plat/amd/versal2/plat_psci_pm.c b/plat/amd/versal2/plat_psci_pm.c
new file mode 100644
index 0000000..50614d5
--- /dev/null
+++ b/plat/amd/versal2/plat_psci_pm.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include "def.h"
+#include <ipi.h>
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include <pm_common.h>
+#include "pm_defs.h"
+#include "pm_svc_main.h"
+
+static uintptr_t sec_entry;
+
+static int32_t versal2_pwr_domain_on(u_register_t mpidr)
+{
+	int32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+	int32_t ret = (int32_t) PSCI_E_INTERN_FAIL;
+	enum pm_ret_status pm_ret;
+	const struct pm_proc *proc;
+
+	if (cpu_id != -1) {
+		proc = pm_get_proc((uint32_t)cpu_id);
+		if (proc != NULL) {
+			pm_ret = pm_req_wakeup(proc->node_id,
+					       (uint32_t)
+					       ((sec_entry & 0xFFFFFFFFU) | 0x1U),
+					       sec_entry >> 32, 0, 0);
+
+			if (pm_ret == PM_RET_SUCCESS) {
+				/* Clear power down request */
+				pm_client_wakeup(proc);
+				ret = (int32_t) PSCI_E_SUCCESS;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * versal2_pwr_domain_off() - Turn off core.
+ * @target_state: Targeted state.
+ */
+static void versal2_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	const struct pm_proc *proc;
+	uint32_t cpu_id = plat_my_core_pos();
+	enum pm_ret_status pm_ret;
+	size_t i;
+
+	proc = pm_get_proc(cpu_id);
+	if (proc == NULL) {
+		ERROR("Failed to get proc %d\n", cpu_id);
+		goto err;
+	}
+
+	for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+	}
+
+	plat_gic_cpuif_disable();
+	/*
+	 * Send request to PMC to power down the appropriate APU CPU
+	 * core.
+	 * According to PSCI specification, CPU_off function does not
+	 * have resume address and CPU core can only be woken up
+	 * invoking CPU_on function, during which resume address will
+	 * be set.
+	 */
+	pm_ret = pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
+			      SECURE_FLAG);
+
+	if (pm_ret != PM_RET_SUCCESS) {
+		ERROR("Failed to power down CPU %d\n", cpu_id);
+	}
+err:
+	return;
+}
+
+/**
+ * versal2_system_reset() - Send the reset request to firmware for the
+ *                          system to reset. This function does not
+ *                          return as it resets system.
+ */
+static void __dead2 versal2_system_reset(void)
+{
+	uint32_t timeout = 10000U;
+	enum pm_ret_status pm_ret;
+	int32_t ret;
+
+	request_cpu_pwrdwn();
+
+	/*
+	 * Send the system reset request to the firmware if power down request
+	 * is not received from firmware.
+	 */
+	if (pwrdwn_req_received == true) {
+		/*
+		 * TODO: shutdown scope for this reset needs be revised once
+		 * we have a clearer understanding of the overall reset scoping
+		 * including the implementation of SYSTEM_RESET2.
+		 */
+		pm_ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+					 pm_get_shutdown_scope(), SECURE_FLAG);
+
+		if (pm_ret != PM_RET_SUCCESS) {
+			WARN("System shutdown failed\n");
+		}
+
+		/*
+		 * Wait for system shutdown request completed and idle callback
+		 * not received.
+		 */
+		do {
+			ret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id,
+						    primary_proc->ipi->remote_ipi_id);
+			udelay(100);
+			timeout--;
+		} while ((ret != (int32_t)IPI_MB_STATUS_RECV_PENDING) && (timeout > 0U));
+	}
+
+	(void)psci_cpu_off();
+
+	while (true) {
+		wfi();
+	}
+}
+
+/**
+ * versal2_pwr_domain_suspend() - Send request to PMC to suspend core.
+ * @target_state: Targeted state.
+ */
+static void versal2_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	const struct pm_proc *proc;
+	uint32_t cpu_id = plat_my_core_pos();
+	uint32_t state;
+	enum pm_ret_status ret;
+	size_t i;
+
+	proc = pm_get_proc(cpu_id);
+	if (proc == NULL) {
+		ERROR("Failed to get proc %d\n", cpu_id);
+		goto err;
+	}
+
+	for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+	}
+
+	plat_gic_cpuif_disable();
+
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		plat_gic_save();
+	}
+
+	state = (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) ?
+		PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+	/* Send request to PMC to suspend this core */
+	ret = pm_self_suspend(proc->node_id, MAX_LATENCY, state, sec_entry,
+			      SECURE_FLAG);
+
+	if (ret != PM_RET_SUCCESS) {
+		ERROR("Failed to power down CPU %d\n", cpu_id);
+	}
+
+err:
+	return;
+}
+
+static void versal2_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	(void)target_state;
+
+	/* Enable the gic cpu interface */
+	plat_gic_pcpu_init();
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_gic_cpuif_enable();
+}
+
+/**
+ * versal2_pwr_domain_suspend_finish() - Performs actions to finish
+ *                                       suspend procedure.
+ * @target_state: Targeted state.
+ */
+static void versal2_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	const struct pm_proc *proc;
+	uint32_t cpu_id = plat_my_core_pos();
+	size_t i;
+
+	proc = pm_get_proc(cpu_id);
+	if (proc == NULL) {
+		ERROR("Failed to get proc %d\n", cpu_id);
+		goto err;
+	}
+
+	for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+	}
+
+	/* Clear the APU power control register for this cpu */
+	pm_client_wakeup(proc);
+
+	/* APU was turned off, so restore GIC context */
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		plat_gic_resume();
+	}
+
+	plat_gic_cpuif_enable();
+
+err:
+	return;
+}
+
+/**
+ * versal2_system_off() - Send the system off request to firmware.
+ *                        This function does not return as it puts core into WFI
+ */
+static void __dead2 versal2_system_off(void)
+{
+	enum pm_ret_status ret;
+
+	/* Send the power down request to the PMC */
+	ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+				 pm_get_shutdown_scope(), SECURE_FLAG);
+
+	if (ret != PM_RET_SUCCESS) {
+		ERROR("System shutdown failed\n");
+	}
+
+	while (true) {
+		wfi();
+	}
+}
+
+/**
+ * versal2_validate_power_state() - Ensure that the power state
+ *                                  parameter in request is valid.
+ * @power_state: Power state of core.
+ * @req_state: Requested state.
+ *
+ * Return: Returns status, either PSCI_E_SUCCESS or reason.
+ */
+static int32_t versal2_validate_power_state(unsigned int power_state,
+					       psci_power_state_t *req_state)
+{
+	uint32_t pstate = psci_get_pstate_type(power_state);
+	int32_t ret = PSCI_E_SUCCESS;
+
+	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+	assert(req_state);
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+	} else {
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+	}
+
+	/* The 'state_id' is expected to be zero */
+	if (psci_get_pstate_id(power_state) != 0U) {
+		ret = PSCI_E_INVALID_PARAMS;
+	}
+
+	return ret;
+}
+
+/**
+ * versal2_get_sys_suspend_power_state() - Get power state for system
+ *                                            suspend.
+ * @req_state: Requested state.
+ */
+static void versal2_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	uint64_t i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+	}
+}
+
+/**
+ * Export the platform specific power ops.
+ */
+static const struct plat_psci_ops versal2_nopmc_psci_ops = {
+	.pwr_domain_on                  = versal2_pwr_domain_on,
+	.pwr_domain_off                 = versal2_pwr_domain_off,
+	.pwr_domain_on_finish           = versal2_pwr_domain_on_finish,
+	.pwr_domain_suspend             = versal2_pwr_domain_suspend,
+	.pwr_domain_suspend_finish      = versal2_pwr_domain_suspend_finish,
+	.system_off                     = versal2_system_off,
+	.system_reset                   = versal2_system_reset,
+	.validate_power_state           = versal2_validate_power_state,
+	.get_sys_suspend_power_state    = versal2_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			    const struct plat_psci_ops **psci_ops)
+{
+	sec_entry = sec_entrypoint;
+
+	VERBOSE("Setting up entry point %lx\n", sec_entry);
+
+	*psci_ops = &versal2_nopmc_psci_ops;
+
+	return 0;
+}
+
+int32_t sip_svc_setup_init(void)
+{
+	return pm_setup();
+}
+
+uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+		     const void *cookie, void *handle, uint64_t flags)
+{
+	return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk
index 3114976..489a063 100644
--- a/plat/amd/versal2/platform.mk
+++ b/plat/amd/versal2/platform.mk
@@ -1,6 +1,6 @@
 # Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
 # Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
-# Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
@@ -28,6 +28,9 @@
 IPI_CRC_CHECK := 0
 GIC_ENABLE_V4_EXTN :=  0
 GICV3_SUPPORT_GIC600 := 1
+TFA_NO_PM := 0
+CPU_PWRDWN_SGI ?= 6
+$(eval $(call add_define_val,CPU_PWR_DOWN_REQ_INTR,ARM_IRQ_SEC_SGI_${CPU_PWRDWN_SGI}))
 
 override CTX_INCLUDE_AARCH32_REGS    := 0
 
@@ -35,6 +38,10 @@
 override PLAT_XLAT_TABLES_DYNAMIC := 1
 $(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
 
+ifdef TFA_NO_PM
+   $(eval $(call add_define,TFA_NO_PM))
+endif
+
 ifdef MEM_BASE
     $(eval $(call add_define,MEM_BASE))
 
@@ -86,13 +93,14 @@
 endif
 endif
 
-
-ifdef XILINX_OF_BOARD_DTB_ADDR
+ifeq (${TRANSFER_LIST},0)
+XILINX_OF_BOARD_DTB_ADDR ?= 0x1000000
 $(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
 endif
 
 PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/			\
 				-Iplat/xilinx/common/include/			\
+				-Iplat/amd/common/include/			\
 				-Iplat/xilinx/common/ipi_mailbox_service/	\
 				-I${PLAT_PATH}/include/				\
 				-Iplat/xilinx/versal/pm_service/
@@ -128,11 +136,17 @@
 				drivers/scmi-msg/reset_domain.c			\
 				${PLAT_PATH}/scmi.c
 
+ifeq ($(TFA_NO_PM), 0)
+BL31_SOURCES		+=	plat/xilinx/common/pm_service/pm_api_sys.c	\
+				plat/xilinx/common/pm_service/pm_ipi.c		\
+				${PLAT_PATH}/plat_psci_pm.c			\
+				${PLAT_PATH}/pm_service/pm_svc_main.c	\
+				${PLAT_PATH}/pm_service/pm_client.c
+else
 BL31_SOURCES		+=	${PLAT_PATH}/plat_psci.c
+endif
 
-BL31_SOURCES		+=	plat/xilinx/common/plat_fdt.c			\
-				common/fdt_wrappers.c                           \
-				plat/xilinx/common/plat_fdt.c                   \
+BL31_SOURCES		+=	common/fdt_wrappers.c                           \
 				plat/xilinx/common/plat_console.c               \
 				plat/xilinx/common/plat_startup.c		\
 				plat/xilinx/common/ipi.c			\
@@ -153,7 +167,20 @@
 endif
 
 # Enable Handoff protocol using transfer lists
-TRANSFER_LIST                   := 1
+TRANSFER_LIST                   ?= 0
 
+ifeq (${TRANSFER_LIST},1)
 include lib/transfer_list/transfer_list.mk
-BL31_SOURCES           +=      plat/xilinx/common/plat_xfer_list.c
+BL31_SOURCES           +=	plat/amd/common/plat_fdt.c
+BL31_SOURCES           +=	plat/amd/common/plat_xfer_list.c
+else
+BL31_SOURCES           +=	plat/xilinx/common/plat_fdt.c
+endif
+
+XLNX_DT_CFG	?= 1
+ifeq (${TRANSFER_LIST},0)
+ifndef XILINX_OF_BOARD_DTB_ADDR
+XLNX_DT_CFG	:= 0
+endif
+endif
+$(eval $(call add_define,XLNX_DT_CFG))
diff --git a/plat/amd/versal2/pm_service/pm_client.c b/plat/amd/versal2/pm_service/pm_client.c
new file mode 100644
index 0000000..8d6b9b1
--- /dev/null
+++ b/plat/amd/versal2/pm_service/pm_client.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include "def.h"
+#include <plat_ipi.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+#define UNDEFINED_CPUID	UINT32_MAX
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
+
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. Therefore, there is no doubt to use the spin_lock here.
+ */
+static spinlock_t pm_client_secure_lock;
+static inline void pm_client_lock_get(void)
+{
+	spin_lock(&pm_client_secure_lock);
+}
+
+static inline void pm_client_lock_release(void)
+{
+	spin_unlock(&pm_client_secure_lock);
+}
+
+static const struct pm_ipi apu_ipi = {
+	.local_ipi_id = IPI_LOCAL_ID,
+	.remote_ipi_id = IPI_REMOTE_ID,
+	.buffer_base = IPI_BUFFER_LOCAL_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+	{
+		.node_id = PM_DEV_CLUSTER0_ACPU_0,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER0_ACPU_1,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER1_ACPU_0,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER1_ACPU_1,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER2_ACPU_0,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER2_ACPU_1,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER3_ACPU_0,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = PM_DEV_CLUSTER3_ACPU_1,
+		.ipi = &apu_ipi,
+	},
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure.
+ * @cpuid: id of the cpu whose proc struct pointer should be returned.
+ *
+ * Return: Pointer to a proc structure if proc is found, otherwise NULL.
+ */
+const struct pm_proc *pm_get_proc(uint32_t cpuid)
+{
+	const struct pm_proc *proc = NULL;
+
+	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+		proc = &pm_procs_all[cpuid];
+	} else {
+		ERROR("cpuid: %d proc NULL\n", cpuid);
+	}
+
+	return proc;
+}
+
+/**
+ * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number.
+ * @irq: Interrupt number.
+ *
+ * Return: PM node index corresponding to the specified interrupt.
+ */
+enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
+{
+	enum pm_device_node_idx dev_idx = XPM_NODEIDX_DEV_MIN;
+
+	assert(irq <= IRQ_MAX);
+
+	switch (irq) {
+	case 11:
+		dev_idx = XPM_NODEIDX_DEV_I2C_2;
+		break;
+	case 12:
+		dev_idx = XPM_NODEIDX_DEV_I2C_3;
+		break;
+	case 13:
+		dev_idx = XPM_NODEIDX_DEV_I2C_4;
+		break;
+	case 20:
+		dev_idx = XPM_NODEIDX_DEV_GPIO;
+		break;
+	case 21:
+		dev_idx = XPM_NODEIDX_DEV_I2C_0;
+		break;
+	case 22:
+		dev_idx = XPM_NODEIDX_DEV_I2C_1;
+		break;
+	case 23:
+		dev_idx = XPM_NODEIDX_DEV_SPI_0;
+		break;
+	case 24:
+		dev_idx = XPM_NODEIDX_DEV_SPI_1;
+		break;
+	case 25:
+		dev_idx = XPM_NODEIDX_DEV_UART_0;
+		break;
+	case 26:
+		dev_idx = XPM_NODEIDX_DEV_UART_1;
+		break;
+	case 27:
+		dev_idx = XPM_NODEIDX_DEV_CAN_FD_0;
+		break;
+	case 28:
+		dev_idx = XPM_NODEIDX_DEV_CAN_FD_1;
+		break;
+	case 29:
+	case 30:
+	case 31:
+	case 32:
+	case 33:
+	case 98:
+		dev_idx = XPM_NODEIDX_DEV_USB_0;
+		break;
+	case 34:
+	case 35:
+	case 36:
+	case 37:
+	case 38:
+	case 99:
+		dev_idx = XPM_NODEIDX_DEV_USB_1;
+		break;
+	case 39:
+	case 40:
+		dev_idx = XPM_NODEIDX_DEV_GEM_0;
+		break;
+	case 41:
+	case 42:
+		dev_idx = XPM_NODEIDX_DEV_GEM_1;
+		break;
+	case 43:
+		dev_idx = XPM_NODEIDX_DEV_TTC_0;
+		break;
+	case 44:
+		dev_idx = XPM_NODEIDX_DEV_TTC_1;
+		break;
+	case 45:
+		dev_idx = XPM_NODEIDX_DEV_TTC_2;
+		break;
+	case 46:
+		dev_idx = XPM_NODEIDX_DEV_TTC_3;
+		break;
+	case 47:
+		dev_idx = XPM_NODEIDX_DEV_TTC_4;
+		break;
+	case 48:
+		dev_idx = XPM_NODEIDX_DEV_TTC_5;
+		break;
+	case 49:
+		dev_idx = XPM_NODEIDX_DEV_TTC_6;
+		break;
+	case 50:
+		dev_idx = XPM_NODEIDX_DEV_TTC_7;
+		break;
+	case 72:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_0;
+		break;
+	case 73:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_1;
+		break;
+	case 74:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_2;
+		break;
+	case 75:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_3;
+		break;
+	case 76:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_4;
+		break;
+	case 77:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_5;
+		break;
+	case 78:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_6;
+		break;
+	case 79:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_7;
+		break;
+	case 95:
+		dev_idx = XPM_NODEIDX_DEV_CAN_FD_2;
+		break;
+	case 96:
+		dev_idx = XPM_NODEIDX_DEV_CAN_FD_3;
+		break;
+	case 100:
+		dev_idx = XPM_NODEIDX_DEV_I2C_5;
+		break;
+	case 101:
+		dev_idx = XPM_NODEIDX_DEV_I2C_6;
+		break;
+	case 102:
+		dev_idx = XPM_NODEIDX_DEV_I2C_7;
+		break;
+	case 200:
+		dev_idx = XPM_NODEIDX_DEV_RTC;
+		break;
+	case 218:
+		dev_idx = XPM_NODEIDX_DEV_SDIO_0;
+		break;
+	case 220:
+		dev_idx = XPM_NODEIDX_DEV_SDIO_1;
+		break;
+	default:
+		dev_idx = XPM_NODEIDX_DEV_MIN;
+		break;
+	}
+
+	return dev_idx;
+}
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions. This function
+ *                       perform actions required prior to sending suspend
+ *                       request.
+ *                       Actions taken depend on the state system is
+ *                       suspending to.
+ * @proc: processor which need to suspend.
+ * @state: desired suspend state.
+ */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+	uintptr_t val;
+	/*
+	 * Get the core index, use it calculate offset for secondary cores
+	 * to match with register database
+	 */
+	uint32_t core_index = cpu_id + ((cpu_id / 2U) * 2U);
+
+	pm_client_lock_get();
+
+	if (state == PM_STATE_SUSPEND_TO_RAM) {
+		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
+	}
+
+	val = read_cpu_pwrctrl_val();
+	val |= CORE_PWRDN_EN_BIT_MASK;
+	write_cpu_pwrctrl_val(val);
+
+	isb();
+
+	/* Enable power down interrupt */
+	mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(core_index),
+		      APU_PCIL_CORE_X_IEN_POWER_MASK);
+	/* Enable wake interrupt */
+	mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(core_index),
+		      APU_PCIL_CORE_X_IEN_WAKE_MASK);
+
+	pm_client_lock_release();
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID.
+ * @nid: node id of the processor.
+ *
+ * Return: the cpu ID (starting from 0) for the subsystem.
+ */
+static uint32_t pm_get_cpuid(uint32_t nid)
+{
+	uint32_t ret = (uint32_t) UNDEFINED_CPUID;
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+		if (pm_procs_all[i].node_id == nid) {
+			ret = (uint32_t)i;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions.
+ * @proc: Processor which need to wakeup.
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core.
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+	uint32_t cpuid = pm_get_cpuid(proc->node_id);
+	uintptr_t val;
+
+	if (cpuid != (uint32_t) UNDEFINED_CPUID) {
+		pm_client_lock_get();
+
+		/* Clear powerdown request */
+		val = read_cpu_pwrctrl_val();
+		val &= ~CORE_PWRDN_EN_BIT_MASK;
+		write_cpu_pwrctrl_val(val);
+
+		isb();
+
+		/* Disabled power down interrupt */
+		mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpuid),
+			      APU_PCIL_CORE_X_IDS_POWER_MASK);
+		/* Disable wake interrupt */
+		mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(cpuid),
+			      APU_PCIL_CORE_X_IDS_WAKE_MASK);
+
+		pm_client_lock_release();
+	}
+}
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions.
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request.
+ */
+void pm_client_abort_suspend(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+	uintptr_t val;
+
+	/* Enable interrupts at processor level (for current cpu) */
+	gicv3_cpuif_enable(plat_my_core_pos());
+
+	pm_client_lock_get();
+
+	/* Clear powerdown request */
+	val = read_cpu_pwrctrl_val();
+	val &= ~CORE_PWRDN_EN_BIT_MASK;
+	write_cpu_pwrctrl_val(val);
+
+	isb();
+
+	/* Disabled power down interrupt */
+	mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
+		      APU_PCIL_CORE_X_IDS_POWER_MASK);
+
+	pm_client_lock_release();
+}
diff --git a/plat/amd/versal2/pm_service/pm_svc_main.c b/plat/amd/versal2/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..88848e2
--- /dev/null
+++ b/plat/amd/versal2/pm_service/pm_svc_main.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for Versal2 power management calls and
+ * IPI setup functions for communication with PMC.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+
+#include <common/runtime_svc.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include "pm_svc_main.h"
+
+#define MODE				0x80000000U
+
+#define INVALID_SGI    0xFFU
+#define PM_INIT_SUSPEND_CB	(30U)
+#define PM_NOTIFY_CB		(32U)
+#define EVENT_CPU_PWRDWN	(4U)
+#define MBOX_SGI_SHARED_IPI	(7U)
+
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ */
+#define upper_32_bits(n)	((uint32_t)((n) >> 32U))
+
+/**
+ * lower_32_bits - return bits 0-31 of a number
+ * @n: the number we're accessing
+ */
+#define lower_32_bits(n)	((uint32_t)((n) & 0xffffffffU))
+
+/**
+ * EXTRACT_SMC_ARGS - extracts 32-bit payloads from 64-bit SMC arguments
+ * @pm_arg: array of 32-bit payloads
+ * @x: array of 64-bit SMC arguments
+ */
+#define EXTRACT_ARGS(pm_arg, x)						\
+	for (uint32_t i = 0U; i < (PAYLOAD_ARG_CNT - 1U); i++) {	\
+		if ((i % 2U) != 0U) {					\
+			pm_arg[i] = lower_32_bits(x[(i / 2U) + 1U]);	\
+		} else {						\
+			pm_arg[i] = upper_32_bits(x[i / 2U]);		\
+		}							\
+	}
+
+/* 1 sec of wait timeout for secondary core down */
+#define PWRDWN_WAIT_TIMEOUT	(1000U)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
+
+/* pm_up = true - UP, pm_up = false - DOWN */
+static bool pm_up;
+static uint32_t sgi = (uint32_t)INVALID_SGI;
+bool pwrdwn_req_received;
+
+static void notify_os(void)
+{
+	plat_ic_raise_ns_sgi((int)sgi, read_mpidr_el1());
+}
+
+static uint64_t cpu_pwrdwn_req_handler(uint32_t id, uint32_t flags,
+				       void *handle, void *cookie)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	VERBOSE("Powering down CPU %d\n", cpu_id);
+
+	/* Deactivate CPU power down SGI */
+	plat_ic_end_of_interrupt(CPU_PWR_DOWN_REQ_INTR);
+
+	return (uint64_t) psci_cpu_off();
+}
+
+/**
+ * raise_pwr_down_interrupt() - Callback function to raise SGI.
+ * @mpidr: MPIDR for the target CPU.
+ *
+ * Raise SGI interrupt to trigger the CPU power down sequence on all the
+ * online secondary cores.
+ */
+static void raise_pwr_down_interrupt(u_register_t mpidr)
+{
+	plat_ic_raise_el3_sgi((int)CPU_PWR_DOWN_REQ_INTR, mpidr);
+}
+
+void request_cpu_pwrdwn(void)
+{
+	int ret;
+
+	VERBOSE("CPU power down request received\n");
+
+	/* Send powerdown request to online secondary core(s) */
+	ret = psci_stop_other_cores(plat_my_core_pos(), (unsigned int)PWRDWN_WAIT_TIMEOUT, raise_pwr_down_interrupt);
+	if (ret != (int)PSCI_E_SUCCESS) {
+		ERROR("Failed to powerdown secondary core(s)\n");
+	}
+
+	/* Clear IPI IRQ */
+	pm_ipi_irq_clear(primary_proc);
+
+	/* Deactivate IPI IRQ */
+	plat_ic_end_of_interrupt(PLAT_VERSAL_IPI_IRQ);
+}
+
+static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
+				void *cookie)
+{
+	uint32_t payload[4] = {0};
+	enum pm_ret_status ret;
+	uint32_t ipi_status, i;
+
+	VERBOSE("Received IPI FIQ from firmware\n");
+
+	console_flush();
+	(void)plat_ic_acknowledge_interrupt();
+
+	/* Check status register for each IPI except PMC */
+	for (i = IPI_ID_APU; i <= IPI_ID_5; i++) {
+		ipi_status = (uint32_t)ipi_mb_enquire_status(IPI_ID_APU, i);
+
+		/* If any agent other than PMC has generated IPI FIQ then send SGI to mbox driver */
+		if ((ipi_status & (uint32_t)IPI_MB_STATUS_RECV_PENDING) > (uint32_t) 0) {
+			plat_ic_raise_ns_sgi((int)MBOX_SGI_SHARED_IPI, read_mpidr_el1());
+			break;
+		}
+	}
+
+	/* If PMC has not generated interrupt then end ISR */
+	ipi_status = (uint32_t)ipi_mb_enquire_status(IPI_ID_APU, IPI_ID_PMC);
+	if ((ipi_status & (uint32_t) IPI_MB_STATUS_RECV_PENDING) == (uint32_t) 0) {
+		plat_ic_end_of_interrupt(id);
+		goto end;
+	}
+
+	/* Handle PMC case */
+	ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
+	if (ret != PM_RET_SUCCESS) {
+		payload[0] = (uint32_t) ret;
+	}
+
+	switch (payload[0]) {
+	case PM_INIT_SUSPEND_CB:
+		if (sgi != INVALID_SGI) {
+			notify_os();
+		}
+		break;
+	case PM_NOTIFY_CB:
+		if (sgi != INVALID_SGI) {
+			if (payload[2] == EVENT_CPU_PWRDWN) {
+				if (pwrdwn_req_received) {
+					pwrdwn_req_received = false;
+					request_cpu_pwrdwn();
+					(void)psci_cpu_off();
+					break;
+				} else {
+					/* No action needed, added for MISRA
+					 * complaince
+					 */
+				}
+				pwrdwn_req_received = true;
+
+			} else {
+				/* No action needed, added for MISRA
+				 * complaince
+				 */
+			}
+			notify_os();
+		} else if (payload[2] == EVENT_CPU_PWRDWN) {
+			request_cpu_pwrdwn();
+			(void)psci_cpu_off();
+		} else {
+			/* No action needed, added for MISRA
+			 * complaince
+			 */
+		}
+		break;
+	case (uint32_t) PM_RET_ERROR_INVALID_CRC:
+		pm_ipi_irq_clear(primary_proc);
+		WARN("Invalid CRC in the payload\n");
+		break;
+
+	default:
+		pm_ipi_irq_clear(primary_proc);
+		WARN("Invalid IPI payload\n");
+		break;
+	}
+
+	/* Clear FIQ */
+	plat_ic_end_of_interrupt(id);
+
+end:
+	return 0;
+}
+
+/**
+ * pm_register_sgi() - PM register the IPI interrupt.
+ * @sgi_num: SGI number to be used for communication.
+ * @reset: Reset to invalid SGI when reset=1.
+ *
+ * Return: On success, the initialization function must return 0.
+ *         Any other return value will cause the framework to ignore
+ *         the service.
+ *
+ * Update the SGI number to be used.
+ *
+ */
+int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset)
+{
+	int32_t ret;
+
+	if (reset == 1U) {
+		sgi = INVALID_SGI;
+		ret = 0;
+		goto end;
+	}
+
+	if (sgi != INVALID_SGI) {
+		ret = -EBUSY;
+		goto end;
+	}
+
+	if (sgi_num >= GICV3_MAX_SGI_TARGETS) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	sgi = (uint32_t)sgi_num;
+	ret = 0;
+end:
+	return ret;
+}
+
+/**
+ * pm_setup() - PM service setup.
+ *
+ * Return: On success, the initialization function must return 0.
+ *         Any other return value will cause the framework to ignore
+ *         the service.
+ *
+ * Initialization functions for Versal power management for
+ * communicaton with PMC.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ *
+ */
+int32_t pm_setup(void)
+{
+	int32_t ret = 0;
+
+	pm_ipi_init(primary_proc);
+	pm_up = true;
+
+	/* register SGI handler for CPU power down request */
+	ret = request_intr_type_el3(CPU_PWR_DOWN_REQ_INTR, cpu_pwrdwn_req_handler);
+	if (ret != 0) {
+		WARN("BL31: registering SGI interrupt failed\n");
+	}
+
+	/*
+	 * Enable IPI IRQ
+	 * assume the rich OS is OK to handle callback IRQs now.
+	 * Even if we were wrong, it would not enable the IRQ in
+	 * the GIC.
+	 */
+	pm_ipi_irq_enable(primary_proc);
+
+	ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler);
+	if (ret != 0) {
+		WARN("BL31: registering IPI interrupt failed\n");
+	}
+
+	gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE);
+
+	/* Register for idle callback during force power down/restart */
+	ret = (int32_t)pm_register_notifier(primary_proc->node_id, EVENT_CPU_PWRDWN,
+				   0x0U, 0x1U, SECURE_FLAG);
+	if (ret != 0) {
+		WARN("BL31: registering idle callback for restart/force power down failed\n");
+	}
+
+	return ret;
+}
+
+/**
+ * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * These EEMI APIs performs CPU specific power management tasks.
+ * These EEMI APIs are invoked either from PSCI or from debugfs in kernel.
+ * These calls require CPU specific processing before sending IPI request to
+ * Platform Management Controller. For example enable/disable CPU specific
+ * interrupts. This requires separate handler for these calls and may not be
+ * handled using common eemi handler.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0.
+ *
+ */
+static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg,
+					   void *handle, uint32_t security_flag)
+{
+	enum pm_ret_status ret;
+
+	switch (api_id) {
+
+	case (uint32_t)PM_SELF_SUSPEND:
+		ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+				      pm_arg[3], security_flag);
+		SMC_RET1(handle, (u_register_t)ret);
+
+	case (uint32_t)PM_FORCE_POWERDOWN:
+		ret = pm_force_powerdown(pm_arg[0], (uint8_t)pm_arg[1], security_flag);
+		SMC_RET1(handle, (u_register_t)ret);
+
+	case (uint32_t)PM_REQ_SUSPEND:
+		ret = pm_req_suspend(pm_arg[0], (uint8_t)pm_arg[1], pm_arg[2],
+				     pm_arg[3], security_flag);
+		SMC_RET1(handle, (u_register_t)ret);
+
+	case (uint32_t)PM_ABORT_SUSPEND:
+		ret = pm_abort_suspend(pm_arg[0], security_flag);
+		SMC_RET1(handle, (u_register_t)ret);
+
+	case (uint32_t)PM_SYSTEM_SHUTDOWN:
+		ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag);
+		SMC_RET1(handle, (u_register_t)ret);
+
+	default:
+		return (uintptr_t)0;
+	}
+}
+
+/**
+ * TF_A_specific_handler() - SMC handler for TF-A specific functionality.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * These EEMI calls performs functionality that does not require
+ * IPI transaction. The handler ends in TF-A and returns requested data to
+ * kernel from TF-A.
+ *
+ * Return: If TF-A specific API found then, uintptr_t type address, else 0
+ *
+ */
+static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
+				       void *handle, uint32_t security_flag)
+{
+	switch (api_id) {
+
+	case TF_A_FEATURE_CHECK:
+	{
+		enum pm_ret_status ret;
+		uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+
+		ret = eemi_feature_check(pm_arg[0], result);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U));
+	}
+
+	case TF_A_PM_REGISTER_SGI:
+	{
+		int32_t ret;
+
+		ret = pm_register_sgi(pm_arg[0], pm_arg[1]);
+		if (ret != 0) {
+			SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS);
+		}
+
+		SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS);
+	}
+
+	case PM_GET_CALLBACK_DATA:
+	{
+		uint32_t result[4] = {0};
+		enum pm_ret_status ret;
+
+		ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
+		if (ret != PM_RET_SUCCESS) {
+			result[0] = (uint32_t) ret;
+		}
+
+		SMC_RET2(handle,
+			(uint64_t)result[0] | ((uint64_t)result[1] << 32U),
+			(uint64_t)result[2] | ((uint64_t)result[3] << 32U));
+	}
+
+	case PM_GET_TRUSTZONE_VERSION:
+		SMC_RET1(handle, ((uint64_t)PM_RET_SUCCESS) |
+			 (((uint64_t)TZ_VERSION) << 32U));
+
+	default:
+		return (uintptr_t)0U;
+	}
+}
+
+/**
+ * eemi_api_handler() - Prepare EEMI payload and perform IPI transaction.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * EEMI - Embedded Energy Management Interface is AMD-Xilinx proprietary
+ * protocol to allow communication between power management controller and
+ * different processing clusters.
+ *
+ * This handler prepares EEMI protocol payload received from kernel and performs
+ * IPI transaction.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0
+ */
+static uintptr_t eemi_api_handler(uint32_t api_id, const uint32_t *pm_arg,
+				  void *handle, uint32_t security_flag)
+{
+	enum pm_ret_status ret;
+	uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0U};
+	uint32_t payload[PAYLOAD_ARG_CNT] = {0U};
+	uint32_t module_id;
+
+	module_id = (api_id & MODULE_ID_MASK) >> 8U;
+
+	PM_PACK_PAYLOAD7(payload, module_id, security_flag, api_id,
+			 pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
+			 pm_arg[4], pm_arg[5]);
+
+	ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
+			       RET_PAYLOAD_ARG_CNT);
+
+	SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
+		 (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
+		 (uint64_t)buf[3] | ((uint64_t)buf[4] << 32U),
+		 (uint64_t)buf[5]);
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid: Function Identifier.
+ * @x1: SMC64 Arguments from kernel.
+ * @x2: SMC64 Arguments from kernel.
+ * @x3: SMC64 Arguments from kernel (upper 32-bits).
+ * @x4: Unused.
+ * @cookie: Unused.
+ * @handle: Pointer to caller's context structure.
+ * @flags: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * Return: Unused.
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID.
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature.
+ *
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+			uint64_t x4, const void *cookie, void *handle, uint64_t flags)
+{
+	uintptr_t ret;
+	uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
+	uint32_t security_flag = NON_SECURE_FLAG;
+	uint32_t api_id;
+	bool status = false, status_tmp = false;
+	uint64_t x[4] = {x1, x2, x3, x4};
+
+	/* Handle case where PM wasn't initialized properly */
+	if (pm_up == false) {
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+	/*
+	 * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as secure (0)
+	 * if smc called is secure
+	 *
+	 * Add redundant macro call to immune the code from glitches
+	 */
+	SECURE_REDUNDANT_CALL(status, status_tmp, is_caller_secure, flags);
+	if ((status != false) && (status_tmp != false)) {
+		security_flag = SECURE_FLAG;
+	}
+
+	if ((smc_fid & FUNCID_NUM_MASK) == PASS_THROUGH_FW_CMD_ID) {
+		api_id = lower_32_bits(x[0]);
+
+		EXTRACT_ARGS(pm_arg, x);
+
+		return eemi_api_handler(api_id, pm_arg, handle, security_flag);
+	}
+
+	pm_arg[0] = (uint32_t)x1;
+	pm_arg[1] = (uint32_t)(x1 >> 32U);
+	pm_arg[2] = (uint32_t)x2;
+	pm_arg[3] = (uint32_t)(x2 >> 32U);
+	pm_arg[4] = (uint32_t)x3;
+	(void)(x4);
+	api_id = smc_fid & FUNCID_NUM_MASK;
+
+	ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, (uint32_t)flags);
+	if (ret !=  (uintptr_t)0)
+		goto error;
+
+	ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag);
+	if (ret !=  (uintptr_t)0)
+		goto error;
+
+error:
+	return ret;
+}
diff --git a/plat/amd/versal2/sip_svc_setup.c b/plat/amd/versal2/sip_svc_setup.c
index 4a1be3e..9e81af0 100644
--- a/plat/amd/versal2/sip_svc_setup.c
+++ b/plat/amd/versal2/sip_svc_setup.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,7 +27,7 @@
 
 /* SiP Service Calls version numbers */
 #define SIP_SVC_VERSION_MAJOR		(0U)
-#define SIP_SVC_VERSION_MINOR		(1U)
+#define SIP_SVC_VERSION_MINOR		(2U)
 
 /* These macros are used to identify PM calls from the SMC function ID */
 #define SIP_FID_MASK	GENMASK(23, 16)
diff --git a/plat/amlogic/axg/axg_pm.c b/plat/amlogic/axg/axg_pm.c
index e67f263..8a1b5d2 100644
--- a/plat/amlogic/axg/axg_pm.c
+++ b/plat/amlogic/axg/axg_pm.c
@@ -152,7 +152,7 @@
 	.pwr_domain_on			= axg_pwr_domain_on,
 	.pwr_domain_on_finish		= axg_pwr_domain_on_finish,
 	.pwr_domain_off			= axg_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi	= axg_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down		= axg_pwr_domain_pwr_down_wfi,
 	.system_off			= axg_system_off,
 	.system_reset			= axg_system_reset
 };
diff --git a/plat/amlogic/g12a/g12a_pm.c b/plat/amlogic/g12a/g12a_pm.c
index c9fe3e9..1203e3c 100644
--- a/plat/amlogic/g12a/g12a_pm.c
+++ b/plat/amlogic/g12a/g12a_pm.c
@@ -200,7 +200,7 @@
 	.pwr_domain_on			= g12a_pwr_domain_on,
 	.pwr_domain_on_finish		= g12a_pwr_domain_on_finish,
 	.pwr_domain_off			= g12a_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi	= g12a_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down		= g12a_pwr_domain_pwr_down_wfi,
 	.system_off			= g12a_system_off,
 	.system_reset			= g12a_system_reset
 };
diff --git a/plat/amlogic/gxbb/gxbb_pm.c b/plat/amlogic/gxbb/gxbb_pm.c
index 48bff7b..eeebb41 100644
--- a/plat/amlogic/gxbb/gxbb_pm.c
+++ b/plat/amlogic/gxbb/gxbb_pm.c
@@ -176,7 +176,7 @@
 	.pwr_domain_on			= gxbb_pwr_domain_on,
 	.pwr_domain_on_finish		= gxbb_pwr_domain_on_finish,
 	.pwr_domain_off			= gxbb_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi	= gxbb_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down		= gxbb_pwr_domain_pwr_down_wfi,
 	.system_off			= gxbb_system_off,
 	.system_reset			= gxbb_system_reset,
 };
diff --git a/plat/amlogic/gxl/gxl_pm.c b/plat/amlogic/gxl/gxl_pm.c
index 433140b..5af4932 100644
--- a/plat/amlogic/gxl/gxl_pm.c
+++ b/plat/amlogic/gxl/gxl_pm.c
@@ -199,7 +199,7 @@
 	.pwr_domain_on			= gxl_pwr_domain_on,
 	.pwr_domain_on_finish		= gxl_pwr_domain_on_finish,
 	.pwr_domain_off			= gxl_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi	= gxl_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down		= gxl_pwr_domain_pwr_down_wfi,
 	.system_off			= gxl_system_off,
 	.system_reset			= gxl_system_reset,
 };
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
index 967bf21..31835f1 100644
--- a/plat/arm/board/arm_fpga/platform.mk
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -78,7 +78,6 @@
 				lib/cpus/aarch64/cortex_a720.S			\
 				lib/cpus/aarch64/cortex_x3.S 			\
 				lib/cpus/aarch64/cortex_x4.S			\
-				lib/cpus/aarch64/neoverse_n_common.S		\
 				lib/cpus/aarch64/neoverse_n1.S			\
 				lib/cpus/aarch64/neoverse_n2.S			\
 				lib/cpus/aarch64/neoverse_v1.S			\
diff --git a/plat/arm/board/automotive_rd/platform/rd1ae/platform.mk b/plat/arm/board/automotive_rd/platform/rd1ae/platform.mk
index 6773ae0..12b1e8c 100644
--- a/plat/arm/board/automotive_rd/platform/rd1ae/platform.mk
+++ b/plat/arm/board/automotive_rd/platform/rd1ae/platform.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2024, Arm Limited. All rights reserved.
+# Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -33,7 +33,7 @@
 GICV3_SUPPORT_GIC600			:=	1
 HW_ASSISTED_COHERENCY			:=	1
 NEED_BL32				:=	yes
-PLAT_MHU_VERSION			:=	1
+PLAT_MHU				:=	MHUv1
 RESET_TO_BL2				:=	1
 SVE_VECTOR_LEN				:=	128
 USE_COHERENT_MEM			:=	0
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
index 889b8b3..3a6637f 100644
--- a/plat/arm/board/common/board_common.mk
+++ b/plat/arm/board/common/board_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -148,14 +148,14 @@
 $(BUILD_PLAT)/bl2/arm_dev_swd_rotpk.o: $(ARM_SWD_ROTPK)
 endif
 
-$(ARM_PROTPK): $(ARM_PROT_KEY)
+$(ARM_PROTPK): $(ARM_PROT_KEY) | $$(@D)/
 ifndef ARM_PROT_KEY
 	$(error Cannot generate hash: no PROT_KEY defined)
 endif
 	${OPENSSL_BIN_PATH}/openssl ${CRYPTO_ALG} -in ${ARM_PROT_KEY} -pubout -outform DER | \
 	${OPENSSL_BIN_PATH}/openssl dgst -${HASH_ALG} -binary -out $@
 
-$(ARM_SWD_ROTPK): $(ARM_SWD_ROT_KEY)
+$(ARM_SWD_ROTPK): $(ARM_SWD_ROT_KEY) | $$(@D)/
 ifndef ARM_SWD_ROT_KEY
 	$(error Cannot generate hash: no SWD_KEY defined)
 endif
diff --git a/plat/arm/board/corstone1000/common/corstone1000_pm.c b/plat/arm/board/corstone1000/common/corstone1000_pm.c
index bd3faec..5264187 100644
--- a/plat/arm/board/corstone1000/common/corstone1000_pm.c
+++ b/plat/arm/board/corstone1000/common/corstone1000_pm.c
@@ -14,7 +14,7 @@
  * platform layer will take care of registering the handlers with PSCI.
  ******************************************************************************/
 
-static void __dead2 corstone1000_system_reset(void)
+static void corstone1000_system_reset(void)
 {
 
 	uint32_t volatile * const watchdog_ctrl_reg = (uint32_t *) SECURE_WATCHDOG_ADDR_CTRL_REG;
@@ -31,9 +31,6 @@
 
 	*(watchdog_val_reg) = SECURE_WATCHDOG_COUNTDOWN_VAL;
 	*watchdog_ctrl_reg = SECURE_WATCHDOG_MASK_ENABLE;
-	while (1) {
-		wfi();
-	}
 }
 
 #if defined(CORSTONE1000_FVP_MULTICORE)
diff --git a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
index 43dc17b..662b8a4 100644
--- a/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
+++ b/plat/arm/board/fvp/fconf/fconf_hw_config_getter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,7 +18,8 @@
 struct hw_topology_t soc_topology;
 struct uart_serial_config_t uart_serial_config;
 struct cpu_timer_t cpu_timer;
-struct ns_dram_layout dram_layout;
+struct dram_layout_t dram_layout;
+struct pci_props_t pci_props;
 
 /*
  * Each NS DRAM bank entry is 'reg' node property which is
@@ -27,6 +28,7 @@
 #define DRAM_ENTRY_SIZE		(4UL * sizeof(uint32_t))
 
 CASSERT(ARM_DRAM_NUM_BANKS == 2UL, ARM_DRAM_NUM_BANKS_mismatch);
+CASSERT(ARM_PCI_NUM_REGIONS == 2UL, ARM_PCI_NUM_REGIONS_mismatch);
 
 #define ILLEGAL_ADDR	ULL(~0)
 
@@ -352,8 +354,98 @@
 	return 0;
 }
 
+/*
+ * Each PCIe memory region entry is 'ranges' node property which is
+ * an arbitrary number of (child-bus-address, parent-bus-address, length)
+ * triplets. E.g. with
+ * #address-cells = <3>
+ * #size-cells = <2>
+ * parent's #address-cells = <2>
+ * each entry occupies 7 32-bit words.
+ */
+int fconf_populate_pci_props(uintptr_t config)
+{
+	int node, parent, len, err;
+	int parent_ac, ac, sc, entry_len;
+	const uint32_t *reg, *ranges;
+
+	/* Necessary to work with libfdt APIs */
+	const void *hw_config_dtb = (const void *)config;
+
+	/* Find 'pci' node */
+	node = fdt_node_offset_by_prop_value(hw_config_dtb, -1, "device_type",
+					     "pci", sizeof("pci"));
+	if (node < 0) {
+		WARN("FCONF: Unable to locate 'pci' node\n");
+		pci_props.ecam_base = 0UL;
+		pci_props.size = 0UL;
+		pci_props.num_ncoh_regions = 0UL;
+		/* Don't return error code if 'pci' node not found */
+		return 0;
+	}
+
+	reg = fdt_getprop(hw_config_dtb, node, "reg", &len);
+	if (reg == NULL) {
+		ERROR("FCONF failed to read 'reg' property\n");
+		return len;
+	}
+
+	err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0,
+					 (uintptr_t *)&pci_props.ecam_base,
+					 (size_t *)&pci_props.size);
+	if (err < 0) {
+		ERROR("FCONF: Failed to read 'reg' property of 'pci' node\n");
+		return err;
+	}
+
+	parent = fdt_parent_offset(hw_config_dtb, node);
+	if (parent < 0) {
+		return -FDT_ERR_BADOFFSET;
+	}
+
+	parent_ac = fdt_address_cells(hw_config_dtb, parent);
+	ac = fdt_address_cells(hw_config_dtb, node);
+	sc = fdt_size_cells(hw_config_dtb, node);
+
+	entry_len = parent_ac + ac + sc;
+
+	ranges = fdt_getprop(hw_config_dtb, node, "ranges", &len);
+	if (ranges == NULL) {
+		ERROR("FCONF failed to read 'ranges' property\n");
+		return len;
+	}
+
+	/* 'ranges' length in 32-bit words */
+	len /= sizeof(uint32_t);
+	if ((len % entry_len) != 0) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	pci_props.num_ncoh_regions = (uint64_t)(len / entry_len);
+
+	if (pci_props.num_ncoh_regions > ARM_PCI_NUM_REGIONS) {
+		WARN("FCONF: 'ranges' reports more memory regions than supported\n");
+		pci_props.num_ncoh_regions = ARM_PCI_NUM_REGIONS;
+	}
+
+	for (unsigned int i = 0U; i < (unsigned int)pci_props.num_ncoh_regions; i++) {
+		unsigned int cell = i * entry_len + ac;
+
+		/* Read CPU address (parent-bus-address) space */
+		pci_props.ncoh_regions[i].base =
+			fdt_read_prop_cells(&ranges[cell], ac);
+
+		/* Read CPU address size */
+		pci_props.ncoh_regions[i].size =
+			fdt_read_prop_cells(&ranges[cell + parent_ac], sc);
+	}
+
+	return 0;
+}
+
 FCONF_REGISTER_POPULATOR(HW_CONFIG, gicv3_config, fconf_populate_gicv3_config);
 FCONF_REGISTER_POPULATOR(HW_CONFIG, topology, fconf_populate_topology);
 FCONF_REGISTER_POPULATOR(HW_CONFIG, uart_config, fconf_populate_uart_config);
 FCONF_REGISTER_POPULATOR(HW_CONFIG, cpu_timer, fconf_populate_cpu_timer);
 FCONF_REGISTER_POPULATOR(HW_CONFIG, dram_layout, fconf_populate_dram_layout);
+FCONF_REGISTER_POPULATOR(HW_CONFIG, pci_props, fconf_populate_pci_props);
diff --git a/plat/arm/board/fvp/fdts/fvp_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
index 5d58731..a11c1de 100644
--- a/plat/arm/board/fvp/fdts/fvp_fw_config.dts
+++ b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,10 @@
 #include <common/tbbr/tbbr_img_def.h>
 #include <platform_def.h>
 
+/* DTB load addresses */
+#define TB_SOC_FW_ADDR	(ARM_BL_RAM_BASE + 0x300)
+#define TOS_FW_ADDR	(ARM_BL_RAM_BASE + 0x500)
+
 /dts-v1/;
 
 / {
@@ -14,7 +18,7 @@
 		compatible = "fconf,dyn_cfg-dtb_registry";
 
 		tb_fw-config {
-			load-address = <0x0 0x4001300>;
+			load-address = <0x0 TB_SOC_FW_ADDR>;
 			max-size = <0x1800>;
 			id = <TB_FW_CONFIG_ID>;
 		};
@@ -33,7 +37,7 @@
 		 * is loaded at base of DRAM.
 		 */
 		soc_fw-config {
-			load-address = <0x0 0x04001300>;
+			load-address = <0x0 TB_SOC_FW_ADDR>;
 			max-size = <0x200>;
 			id = <SOC_FW_CONFIG_ID>;
 		};
@@ -41,8 +45,7 @@
 /* If required, SPD should enable loading of trusted OS fw config */
 #if defined(SPD_tspd) || defined(SPD_spmd)
 		tos_fw-config {
-
-			load-address = <0x0 0x04001500>;
+			load-address = <0x0 TOS_FW_ADDR>;
 #if ENABLE_RME
 			secondary-load-address = <0x0 0x7e00000>;
 #endif /* ENABLE_RME */
@@ -50,7 +53,6 @@
 			id = <TOS_FW_CONFIG_ID>;
 		};
 #endif
-
 		nt_fw-config {
 			load-address = <0x0 0x80000000>;
 			max-size = <0x200>;
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
index bf0e7f3..b62df1a 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -34,7 +34,7 @@
 			debug_name = "cactus-primary";
 			load_address = <0x7000000>;
 			vcpu_count = <8>;
-			mem_size = <1048576>;
+			mem_size = <0x100000>;
 			/*
 			 * Platform specific SiP SMC call handled at EL3. Used
 			 * to pend an interrupt for testing purpose.
@@ -46,21 +46,21 @@
 			debug_name = "cactus-secondary";
 			load_address = <0x7100000>;
 			vcpu_count = <8>;
-			mem_size = <1048576>;
+			mem_size = <0x100000>;
 		};
 		vm3 {
 			is_ffa_partition;
 			debug_name = "cactus-tertiary";
 			load_address = <0x7200000>;
 			vcpu_count = <1>;
-			mem_size = <1048576>;
+			mem_size = <0x300000>;
 		};
 		vm4 {
 			is_ffa_partition;
 			debug_name = "ivy";
 			load_address = <0x7600000>;
 			vcpu_count = <1>;
-			mem_size = <1048576>;
+			mem_size = <0x100000>;
 		};
 	};
 
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
index 8dcdd62..90d9608 100644
--- a/plat/arm/board/fvp/fvp_bl2_setup.c
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -30,21 +30,25 @@
 	ARM_PAS_SECURE,
 	ARM_PAS_REALM,
 	ARM_PAS_EL3_DRAM,
+#ifdef ARM_PAS_GPTS
 	ARM_PAS_GPTS,
-	ARM_PAS_KERNEL_1
+#endif
+	ARM_PAS_KERNEL_1,
+	ARM_PAS_PCI_MEM_1,
+	ARM_PAS_PCI_MEM_2
 };
 
 static const arm_gpt_info_t arm_gpt_info = {
 	.pas_region_base  = pas_regions,
 	.pas_region_count = (unsigned int)ARRAY_SIZE(pas_regions),
-	.l0_base = (uintptr_t)ARM_L0_GPT_BASE,
-	.l1_base = (uintptr_t)ARM_L1_GPT_BASE,
-	.l0_size = (size_t)ARM_L0_GPT_SIZE,
-	.l1_size = (size_t)ARM_L1_GPT_SIZE,
-	.pps = GPCCR_PPS_64GB,
+	.l0_base = ARM_L0_GPT_BASE,
+	.l1_base = ARM_L1_GPT_BASE,
+	.l0_size = ARM_L0_GPT_SIZE,
+	.l1_size = ARM_L1_GPT_SIZE,
+	.pps = GPCCR_PPS_1TB,
 	.pgs = GPCCR_PGS_4K
 };
-#endif
+#endif /* ENABLE_RME */
 
 void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
 {
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index bdc2cac..7d76814 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -34,12 +34,11 @@
 #define FVP_GICV2		1
 #define FVP_GICV3		2
 
-/* Defines for RMM Console*/
+/* Defines for RMM Console */
 #define FVP_RMM_CONSOLE_BASE		UL(0x1c0c0000)
 #define FVP_RMM_CONSOLE_BAUD		UL(115200)
 #define FVP_RMM_CONSOLE_CLK_IN_HZ	UL(14745600)
 #define FVP_RMM_CONSOLE_NAME		"pl011"
-
 #define FVP_RMM_CONSOLE_COUNT		UL(1)
 
 /*******************************************************************************
@@ -53,7 +52,7 @@
 
 #define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
 					DEVICE0_SIZE,			\
-					MT_DEVICE | MT_RW | MT_SECURE)
+					MT_DEVICE | MT_RW | EL3_PAS)
 
 #define MAP_DEVICE1	MAP_REGION_FLAT(DEVICE1_BASE,			\
 					DEVICE1_SIZE,			\
@@ -591,11 +590,78 @@
 
 	return sum;
 }
-
+/*
+ * Boot Manifest structure illustration, with two DRAM banks,
+ * a single console and one device memory with two PCIe device
+ * non-coherent address ranges.
+ *
+ * +--------------------------------------------------+
+ * | offset |        field       |      comment       |
+ * +--------+--------------------+--------------------+
+ * |   0    |       version      |     0x00000004     |
+ * +--------+--------------------+--------------------+
+ * |   4    |       padding      |     0x00000000     |
+ * +--------+--------------------+--------------------+
+ * |   8    |      plat_data     |       NULL         |
+ * +--------+--------------------+--------------------+
+ * |   16   |      num_banks     |                    |
+ * +--------+--------------------+                    |
+ * |   24   |       banks        |     plat_dram      +--+
+ * +--------+--------------------+                    |  |
+ * |   32   |      checksum      |                    |  |
+ * +--------+--------------------+--------------------+  |
+ * |   40   |    num_consoles    |                    |  |
+ * +--------+--------------------+                    |  |
+ * |   48   |      consoles      |    plat_console    +--|--+
+ * +--------+--------------------+                    |  |  |
+ * |   56   |      checksum      |                    |  |  |
+ * +--------+--------------------+--------------------+  |  |
+ * |   64   |      num_banks     |                    |  |  |
+ * +--------+--------------------+                    |  |  |
+ * |   72   |        banks       |  plat_ncoh_region  +--|--|--+
+ * +--------+--------------------+                    |  |  |  |
+ * |   80   |      checksum      |                    |  |  |  |
+ * +--------+--------------------+--------------------+  |  |  |
+ * |   88   |      num_banks     |                    |  |  |  |
+ * +--------+--------------------+                    |  |  |  |
+ * |   96   |       banks        |   plat_coh_region  |  |  |  |
+ * +--------+--------------------+                    |  |  |  |
+ * |   104  |      checksum      |                    |  |  |  |
+ * +--------+--------------------+--------------------+<-+  |  |
+ * |   112  |       base 0       |                    |     |  |
+ * +--------+--------------------+     mem_bank[0]    |     |  |
+ * |   120  |       size 0       |                    |     |  |
+ * +--------+--------------------+--------------------+     |  |
+ * |   128  |       base 1       |                    |     |  |
+ * +--------+--------------------+     mem_bank[1]    |     |  |
+ * |   136  |       size 1       |                    |     |  |
+ * +--------+--------------------+--------------------+<----+  |
+ * |   144  |       base         |                    |        |
+ * +--------+--------------------+                    |        |
+ * |   152  |      map_pages     |                    |        |
+ * +--------+--------------------+                    |        |
+ * |   160  |       name         |                    |        |
+ * +--------+--------------------+     consoles[0]    |        |
+ * |   168  |     clk_in_hz      |                    |        |
+ * +--------+--------------------+                    |        |
+ * |   176  |     baud_rate      |                    |        |
+ * +--------+--------------------+                    |        |
+ * |   184  |       flags        |                    |        |
+ * +--------+--------------------+--------------------+<-------+
+ * |   192  |       base 0       |                    |
+ * +--------+--------------------+   ncoh_region[0]   |
+ * |   200  |       size 0       |                    |
+ * +--------+--------------------+--------------------+
+ * |   208  |       base 1       |                    |
+ * +--------+--------------------+   ncoh_region[1]   |
+ * |   216  |       size 1       |                    |
+ * +--------+--------------------+--------------------+
+ */
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest)
 {
 	uint64_t checksum, num_banks, num_consoles;
-	struct ns_dram_bank *bank_ptr;
+	uint64_t num_ncoh_regions, num_coh_regions;
+	struct memory_bank *bank_ptr, *ncoh_region_ptr;
 	struct console_info *console_ptr;
 
 	assert(manifest != NULL);
@@ -607,71 +673,45 @@
 	/* Set number of consoles */
 	num_consoles = FVP_RMM_CONSOLE_COUNT;
 
+	/* Set number of device non-coherent address ranges based on DT */
+	num_ncoh_regions = FCONF_GET_PROPERTY(hw_config, pci_props, num_ncoh_regions);
+
 	manifest->version = RMMD_MANIFEST_VERSION;
 	manifest->padding = 0U; /* RES0 */
-	manifest->plat_data = (uintptr_t)NULL;
+	manifest->plat_data = 0UL;
 	manifest->plat_dram.num_banks = num_banks;
 	manifest->plat_console.num_consoles = num_consoles;
+	manifest->plat_ncoh_region.num_banks = num_ncoh_regions;
 
-	/*
-	 * Boot Manifest structure illustration, with two dram banks and
-	 * a single console.
-	 *
-	 * +----------------------------------------+
-	 * | offset |     field      |    comment   |
-	 * +--------+----------------+--------------+
-	 * |   0    |    version     |  0x00000003  |
-	 * +--------+----------------+--------------+
-	 * |   4    |    padding     |  0x00000000  |
-	 * +--------+----------------+--------------+
-	 * |   8    |   plat_data    |     NULL     |
-	 * +--------+----------------+--------------+
-	 * |   16   |   num_banks    |              |
-	 * +--------+----------------+              |
-	 * |   24   |     banks      |   plat_dram  |
-	 * +--------+----------------+              |
-	 * |   32   |    checksum    |              |
-	 * +--------+----------------+--------------+
-	 * |   40   |  num_consoles  |              |
-	 * +--------+----------------+              |
-	 * |   48   |    consoles    | plat_console |
-	 * +--------+----------------+              |
-	 * |   56   |    checksum    |              |
-	 * +--------+----------------+--------------+
-	 * |   64   |     base 0     |              |
-	 * +--------+----------------+    bank[0]   |
-	 * |   72   |     size 0     |              |
-	 * +--------+----------------+--------------+
-	 * |   80   |     base 1     |              |
-	 * +--------+----------------+    bank[1]   |
-	 * |   88   |     size 1     |              |
-	 * +--------+----------------+--------------+
-	 * |   96   |     base       |              |
-	 * +--------+----------------+              |
-	 * |   104  |   map_pages    |              |
-	 * +--------+----------------+              |
-	 * |   112  |     name       |              |
-	 * +--------+----------------+  consoles[0] |
-	 * |   120  |   clk_in_hz    |              |
-	 * +--------+----------------+              |
-	 * |   128  |   baud_rate    |              |
-	 * +--------+----------------+              |
-	 * |   136  |     flags      |              |
-	 * +--------+----------------+--------------+
-	 */
+	/* FVP does not support device coherent address ranges */
+	num_coh_regions = 0UL;
+	manifest->plat_coh_region.num_banks = num_coh_regions;
+	manifest->plat_coh_region.banks = NULL;
+	manifest->plat_coh_region.checksum = 0UL;
 
-	bank_ptr = (struct ns_dram_bank *)
-			(((uintptr_t)manifest) + sizeof(*manifest));
+	bank_ptr = (struct memory_bank *)
+			(((uintptr_t)manifest) + sizeof(struct rmm_manifest));
 	console_ptr = (struct console_info *)
-			((uintptr_t)bank_ptr + (num_banks * sizeof(*bank_ptr)));
-
+			((uintptr_t)bank_ptr + (num_banks *
+						sizeof(struct memory_bank)));
+	ncoh_region_ptr = (struct memory_bank *)
+			((uintptr_t)console_ptr + (num_consoles *
+						sizeof(struct console_info)));
 	manifest->plat_dram.banks = bank_ptr;
 	manifest->plat_console.consoles = console_ptr;
+	manifest->plat_ncoh_region.banks = ncoh_region_ptr;
 
 	/* Ensure the manifest is not larger than the shared buffer */
 	assert((sizeof(struct rmm_manifest) +
-		(sizeof(struct console_info) * manifest->plat_console.num_consoles) +
-		(sizeof(struct ns_dram_bank) * manifest->plat_dram.num_banks)) <= ARM_EL3_RMM_SHARED_SIZE);
+		(sizeof(struct memory_bank) *
+			manifest->plat_dram.num_banks) +
+		(sizeof(struct console_info) *
+			manifest->plat_console.num_consoles) +
+		(sizeof(struct memory_bank) *
+			manifest->plat_ncoh_region.num_banks) +
+		(sizeof(struct memory_bank) *
+			manifest->plat_coh_region.num_banks))
+		<= ARM_EL3_RMM_SHARED_SIZE);
 
 	/* Calculate checksum of plat_dram structure */
 	checksum = num_banks + (uint64_t)bank_ptr;
@@ -683,31 +723,56 @@
 	}
 
 	/* Update checksum */
-	checksum += checksum_calc((uint64_t *)bank_ptr, sizeof(struct ns_dram_bank) * num_banks);
+	checksum += checksum_calc((uint64_t *)bank_ptr, sizeof(struct memory_bank) * num_banks);
 
 	/* Checksum must be 0 */
 	manifest->plat_dram.checksum = ~checksum + 1UL;
 
-	/* Calculate the checksum of the plat_consoles structure */
+	/* Calculate the checksum of plat_consoles structure */
 	checksum = num_consoles + (uint64_t)console_ptr;
 
 	/* Zero out the console info struct */
-	(void)memset((void *)console_ptr, '\0', sizeof(struct console_info) * num_consoles);
+	(void)memset((void *)console_ptr, '\0',
+			sizeof(struct console_info) * num_consoles);
 
 	console_ptr[0].base = FVP_RMM_CONSOLE_BASE;
 	console_ptr[0].map_pages = 1UL;
 	console_ptr[0].clk_in_hz = FVP_RMM_CONSOLE_CLK_IN_HZ;
 	console_ptr[0].baud_rate = FVP_RMM_CONSOLE_BAUD;
 
-	(void)strlcpy(console_ptr[0].name, FVP_RMM_CONSOLE_NAME, RMM_CONSOLE_MAX_NAME_LEN - 1UL);
+	(void)strlcpy(console_ptr[0].name, FVP_RMM_CONSOLE_NAME,
+						RMM_CONSOLE_MAX_NAME_LEN - 1UL);
 
 	/* Update checksum */
 	checksum += checksum_calc((uint64_t *)console_ptr,
 					sizeof(struct console_info) * num_consoles);
-
 	/* Checksum must be 0 */
 	manifest->plat_console.checksum = ~checksum + 1UL;
 
+	/*
+	 * Calculate the checksum of device non-coherent address ranges
+	 * info structure
+	 */
+	checksum = num_ncoh_regions + (uint64_t)ncoh_region_ptr;
+
+	/* Zero out the PCIe region info struct */
+	(void)memset((void *)ncoh_region_ptr, 0,
+			sizeof(struct memory_bank) * num_ncoh_regions);
+
+	for (unsigned long i = 0UL; i < num_ncoh_regions; i++) {
+		ncoh_region_ptr[i].base =
+			FCONF_GET_PROPERTY(hw_config, pci_props, ncoh_regions[i].base);
+		ncoh_region_ptr[i].size =
+			FCONF_GET_PROPERTY(hw_config, pci_props, ncoh_regions[i].size);
+	}
+
+	/* Update checksum */
+	checksum += checksum_calc((uint64_t *)ncoh_region_ptr,
+			sizeof(struct memory_bank) * num_ncoh_regions);
+
+	/* Checksum must be 0 */
+	manifest->plat_ncoh_region.checksum = ~checksum + 1UL;
+
 	return 0;
 }
 #endif	/* ENABLE_RME */
diff --git a/plat/arm/board/fvp/fvp_drtm_stub.c b/plat/arm/board/fvp/fvp_drtm_stub.c
index e2bc516..238febd 100644
--- a/plat/arm/board/fvp/fvp_drtm_stub.c
+++ b/plat/arm/board/fvp/fvp_drtm_stub.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -33,3 +33,13 @@
 {
 	return 0ULL;
 }
+
+uint64_t plat_drtm_get_acpi_tables_region_size(void)
+{
+	return 0ULL;
+}
+
+uint64_t plat_drtm_get_dlme_img_auth_features(void)
+{
+	return 0ULL;
+}
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 80dfd2a..2a0bb93 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -295,28 +295,22 @@
 /*******************************************************************************
  * FVP handlers to shutdown/reboot the system
  ******************************************************************************/
-static void __dead2 fvp_system_off(void)
+static void fvp_system_off(void)
 {
 	/* Write the System Configuration Control Register */
 	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
 		V2M_CFGCTRL_START |
 		V2M_CFGCTRL_RW |
 		V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN));
-	wfi();
-	ERROR("FVP System Off: operation not handled.\n");
-	panic();
 }
 
-static void __dead2 fvp_system_reset(void)
+static void fvp_system_reset(void)
 {
 	/* Write the System Configuration Control Register */
 	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
 		V2M_CFGCTRL_START |
 		V2M_CFGCTRL_RW |
 		V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT));
-	wfi();
-	ERROR("FVP System Reset: operation not handled.\n");
-	panic();
 }
 
 static int fvp_node_hw_state(u_register_t target_cpu,
diff --git a/plat/arm/board/fvp/include/fconf_hw_config_getter.h b/plat/arm/board/fvp/include/fconf_hw_config_getter.h
index b7a1247..351f13d 100644
--- a/plat/arm/board/fvp/include/fconf_hw_config_getter.h
+++ b/plat/arm/board/fvp/include/fconf_hw_config_getter.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,6 +18,7 @@
 #define hw_config__uart_serial_config_getter(prop) uart_serial_config.prop
 #define hw_config__cpu_timer_getter(prop) cpu_timer.prop
 #define hw_config__dram_layout_getter(prop) dram_layout.prop
+#define hw_config__pci_props_getter(prop) pci_props.prop
 
 struct gicv3_config_t {
 	uint64_t gicd_base;
@@ -40,21 +41,30 @@
 	uint32_t clock_freq;
 };
 
-struct ns_dram_layout {
+struct dram_layout_t {
 	uint64_t num_banks;
-	struct ns_dram_bank dram_bank[ARM_DRAM_NUM_BANKS];
+	struct memory_bank dram_bank[ARM_DRAM_NUM_BANKS];
 };
 
+struct pci_props_t {
+	uint64_t ecam_base;
+	uint64_t size;
+	uint64_t num_ncoh_regions;
+	struct memory_bank ncoh_regions[ARM_PCI_NUM_REGIONS];
+};
+
 int fconf_populate_gicv3_config(uintptr_t config);
 int fconf_populate_topology(uintptr_t config);
 int fconf_populate_uart_config(uintptr_t config);
 int fconf_populate_cpu_timer(uintptr_t config);
 int fconf_populate_dram_layout(uintptr_t config);
+int fconf_populate_pci_props(uintptr_t config);
 
 extern struct gicv3_config_t gicv3_config;
 extern struct hw_topology_t soc_topology;
 extern struct uart_serial_config_t uart_serial_config;
 extern struct cpu_timer_t cpu_timer;
-extern struct ns_dram_layout dram_layout;
+extern struct dram_layout_t dram_layout;
+extern struct pci_props_t pci_props;
 
 #endif /* FCONF_HW_CONFIG_GETTER_H */
diff --git a/plat/arm/board/fvp/include/fvp_pas_def.h b/plat/arm/board/fvp/include/fvp_pas_def.h
index 4684387..6b97286 100644
--- a/plat/arm/board/fvp/include/fvp_pas_def.h
+++ b/plat/arm/board/fvp/include/fvp_pas_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,34 +17,37 @@
  * The PA space is initially mapped in the GPT as follows:
  *
  * ============================================================================
- * Base Addr| Size        |L? GPT|PAS   |Content                 |Comment
+ * Base Addr | Size        |L? GPT|PAS   |Content                 |Comment
  * ============================================================================
- * 0GB      | 1GB         |L0 GPT|ANY   |TBROM (EL3 code)        |Fixed mapping
- *          |             |      |      |TSRAM (EL3 data)        |
- * 00000000 |             |      |      |IO (incl.UARTs & GIC)   |
+ * 0GB       | 1GB         |L0 GPT|ANY   |TBROM (EL3 code)        |Fixed mapping
+ *           |             |      |      |TSRAM (EL3 data)        |
+ * 00000000  | 40000000    |      |      |IO (incl.UARTs & GIC)   |
  * ----------------------------------------------------------------------------
- * 1GB      | 1GB         |L0 GPT|ANY   |IO                      |Fixed mapping
- * 40000000 |             |      |      |                        |
+ * 1GB       | 1GB         |L0 GPT|ANY   |IO                      |Fixed mapping
+ * 40000000  | 40000000    |      |      |                        |
  * ----------------------------------------------------------------------------
- * 2GB      |2GB-64MB     |L1 GPT|NS    |DRAM (NS Kernel)        |Use T.Descrip
- * 80000000 |             |      |      |                        |
+ * 1GB+256MB | 256MB       |L1 GPT|NS    |PCI Memory Region 1     |Use T.Descrip
+ * 50000000  | 10000000    |      |      |                        |
  * ----------------------------------------------------------------------------
- * 4GB-64MB |64MB-32MB-4MB|L1 GPT|SECURE|DRAM TZC                |Use T.Descrip
- * FC000000 |             |      |      |                        |
+ * 2GB       | 2GB-64MB    |L1 GPT|NS    |DRAM (NS Kernel)        |Use T.Descrip
+ * 80000000  | 7C000000    |      |      |                        |
  * ----------------------------------------------------------------------------
- * 4GB-32MB |             |      |      |                        |
- * -3MB-1MB |32MB         |L1 GPT|REALM |RMM                     |Use T.Descrip
- * FDC00000 |             |      |      |                        |
+ * 4GB-64MB  |64MB-32MB-4MB|L1 GPT|SECURE|DRAM TZC                |Use T.Descrip
+ * FC000000  | 1C00000     |      |      |                        |
  * ----------------------------------------------------------------------------
- * 4GB-3MB  |             |      |      |                        |
- * -1MB     |3MB          |L1 GPT|ROOT  |EL3 DRAM data           |Use T.Descrip
- * FFC00000 |             |      |      |                        |
+ * 4GB-32MB  |             |      |      |                        |
+ * -3MB-1MB  | 32MB        |L1 GPT|REALM |RMM                     |Use T.Descrip
+ * FDC00000  | 2000000     |      |      |                        |
  * ----------------------------------------------------------------------------
- * 4GB-1MB  |1MB          |L1 GPT|ROOT  |DRAM (L1 GPTs, SCP TZC) |Fixed mapping
- * FFF00000 |             |      |      |                        |
+ * 4GB-3MB   |             |      |      |                        |
+ * -1MB      | 4MB         |L1 GPT|ROOT  |EL3 DRAM data, L1 GPTs, |Use T.Descrip
+ * FFC00000  | 400000      |      |      |SCP TZC                 |
  * ----------------------------------------------------------------------------
- * 34GB     |2GB          |L1 GPT|NS    |DRAM (NS Kernel)        |Use T.Descrip
- * 880000000|             |      |      |                        |
+ * 34GB      | 2GB         |L1 GPT|NS    |DRAM (NS Kernel)        |Use T.Descrip
+ * 880000000 | 80000000    |      |      |                        |
+ * ----------------------------------------------------------------------------
+ * 256GB     | 3GB         |L1 GPT|NS    |PCI Memory Region 2     |Use T.Descrip
+ * 4000000000| C0000000    |      |      |(first 3GB only)        |
  * ============================================================================
  *
  * - 4KB of L0 GPT reside in TSRAM, on top of the CONFIG section.
@@ -61,7 +64,7 @@
 
 /* Device memory 0 to 2GB */
 #define ARM_PAS_1_BASE			(U(0))
-#define ARM_PAS_1_SIZE			((ULL(1) << 31)) /* 2GB */
+#define ARM_PAS_1_SIZE			(SZ_2G) /* 2GB */
 
 /* NS memory 2GB to (end - 64MB) */
 #define ARM_PAS_2_BASE			(ARM_PAS_1_BASE + ARM_PAS_1_SIZE)
@@ -77,7 +80,7 @@
 
 /* NS memory 2GB */
 #define	ARM_PAS_4_BASE			ARM_DRAM2_BASE
-#define	ARM_PAS_4_SIZE			((ULL(1) << 31)) /* 2GB */
+#define	ARM_PAS_4_SIZE			(SZ_2G)	/* 2GB */
 
 #define ARM_PAS_GPI_ANY			MAP_GPT_REGION(ARM_PAS_1_BASE, \
 						       ARM_PAS_1_SIZE, \
@@ -94,6 +97,14 @@
 #define	ARM_PAS_KERNEL_1		GPT_MAP_REGION_GRANULE(ARM_PAS_4_BASE, \
 							       ARM_PAS_4_SIZE, \
 							       GPT_GPI_NS)
+
+#define ARM_PAS_PCI_MEM_1		GPT_MAP_REGION_GRANULE(PLAT_ARM_PCI_MEM_1_BASE, \
+							       PLAT_ARM_PCI_MEM_1_SIZE, \
+							       GPT_GPI_NS)
+
+#define	ARM_PAS_PCI_MEM_2		GPT_MAP_REGION_GRANULE(PLAT_ARM_PCI_MEM_2_BASE, \
+							       PLAT_ARM_PCI_MEM_2_SIZE, \
+							       GPT_GPI_NS)
 /*
  * REALM and Shared area share the same PAS, so consider them a single
  * PAS region to configure in GPT.
@@ -102,7 +113,8 @@
 							       (ARM_PAS_SHARED_SIZE + \
 								ARM_REALM_SIZE), \
 							       GPT_GPI_REALM)
-
+/* Check if the EL3 TZC DRAM is contiguous with L1 GPT region. */
+#if (ARM_L1_GPT_BASE != (ARM_EL3_TZC_DRAM1_BASE + ARM_EL3_TZC_DRAM1_SIZE))
 #define ARM_PAS_EL3_DRAM		GPT_MAP_REGION_GRANULE(ARM_EL3_TZC_DRAM1_BASE, \
 							       ARM_EL3_TZC_DRAM1_SIZE, \
 							       GPT_GPI_ROOT)
@@ -110,6 +122,13 @@
 #define	ARM_PAS_GPTS			GPT_MAP_REGION_GRANULE(ARM_L1_GPT_BASE, \
 							       ARM_L1_GPT_SIZE, \
 							       GPT_GPI_ROOT)
+#else
+/* Contiguous ROOT region */
+#define ARM_PAS_EL3_DRAM		GPT_MAP_REGION_GRANULE(ARM_EL3_TZC_DRAM1_BASE,	\
+							       ARM_EL3_TZC_DRAM1_SIZE +	\
+							       ARM_L1_GPT_SIZE, \
+							       GPT_GPI_ROOT)
+#endif
 
 /* GPT Configuration options */
 #define PLATFORM_L0GPTSZ		GPCCR_L0GPTSZ_30BITS
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index df4be8f..f5be8f2 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -54,7 +54,10 @@
 #if ENABLE_RME
 #define PLAT_ARM_RMM_BASE		(RMM_BASE)
 #define PLAT_ARM_RMM_SIZE		(RMM_LIMIT - RMM_BASE)
-#endif
+
+/* Protected physical address size */
+#define PLAT_ARM_PPS			(SZ_1T)
+#endif /* ENABLE_RME */
 
 /*
  * Max size of SPMC is 2MB for fvp. With SPMD enabled this value corresponds to
@@ -65,7 +68,7 @@
 #define PLAT_ARM_SPMC_SIZE		UL(0x200000)  /* 2 MB */
 #endif
 
-/* virtual address used by dynamic mem_protect for chunk_base */
+/* Virtual address used by dynamic mem_protect for chunk_base */
 #define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xc0000000)
 
 /* No SCP in FVP */
@@ -399,11 +402,22 @@
 #define PLAT_ARM_CLUSTER_TO_CCN_ID_MAP	1, 5, 7, 11
 
 /* System timer related constants */
-#define PLAT_ARM_NSTIMER_FRAME_ID		U(1)
+#define PLAT_ARM_NSTIMER_FRAME_ID	U(1)
 
 /* Mailbox base address */
 #define PLAT_ARM_TRUSTED_MAILBOX_BASE	ARM_TRUSTED_SRAM_BASE
 
+/* PCIe memory region 1 (Base Platform RevC only) */
+#define PLAT_ARM_PCI_MEM_1_BASE		(ULL(0x50000000))
+#define PLAT_ARM_PCI_MEM_1_SIZE		(SZ_256M) /* 256MB */
+
+/*
+ * PCIe memory region 2 (Base Platform RevC only)
+ * The full size of the second PCI memory region is 256GB
+ * but for now we only allocate the L1 GPTs for the first 3GB.
+ */
+#define PLAT_ARM_PCI_MEM_2_BASE		(ULL(0x4000000000))
+#define	PLAT_ARM_PCI_MEM_2_SIZE		(3 * SZ_1G) /* 3GB */
 
 /* TrustZone controller related constants
  *
diff --git a/plat/arm/board/fvp/jmptbl_mbedtls_psa.i b/plat/arm/board/fvp/jmptbl_mbedtls_psa.i
new file mode 100644
index 0000000..4eb707b
--- /dev/null
+++ b/plat/arm/board/fvp/jmptbl_mbedtls_psa.i
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform-specific ROMLIB MbedTLS PSA Crypto functions can be added here.
+# During the build process, this file is appended to jmptbl.i
+# if MbedTLS support is required and PSA Crypto is supported.
+#
+# Format:
+# lib   function        [patch]
+# Example:
+# mbedtls psa_crypto_init
+
+mbedtls mbedtls_pk_get_psa_attributes
+mbedtls mbedtls_pk_import_into_psa
+mbedtls psa_crypto_init
+mbedtls psa_destroy_key
+mbedtls psa_verify_message
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index ce06146..7bd2a1d 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -29,9 +29,13 @@
 endif
 # fdts is wrong otherwise
 
-# Size (in kilobytes) of the Trusted SRAM region to  utilize when building for
-# the FVP platform. This option defaults to 256.
+# Size (in kilobytes) of the Trusted SRAM region to utilize when building for
+# the FVP platform.
+ifeq (${ENABLE_RME},1)
+FVP_TRUSTED_SRAM_SIZE		:= 384
+else
 FVP_TRUSTED_SRAM_SIZE		:= 256
+endif
 
 # Macro to enable helpers for running SPM tests. Disabled by default.
 PLAT_TEST_SPM	:= 0
@@ -206,7 +210,6 @@
 					lib/cpus/aarch64/cortex_a715.S		\
 					lib/cpus/aarch64/cortex_a720.S		\
 					lib/cpus/aarch64/cortex_a720_ae.S	\
-					lib/cpus/aarch64/neoverse_n_common.S	\
 					lib/cpus/aarch64/neoverse_n1.S		\
 					lib/cpus/aarch64/neoverse_n2.S		\
 					lib/cpus/aarch64/neoverse_v1.S		\
@@ -222,7 +225,8 @@
 #Include all CPUs to build to support all-errata build.
 ifeq (${ENABLE_ERRATA_ALL},1)
 	BUILD_CPUS_WITH_NO_FVP_MODEL = 1
-	FVP_CPU_LIBS    +=	lib/cpus/aarch64/cortex_a510.S		\
+	FVP_CPU_LIBS    +=    	lib/cpus/aarch64/cortex_a320.S          \
+				lib/cpus/aarch64/cortex_a510.S		\
 				lib/cpus/aarch64/cortex_a520.S		\
 				lib/cpus/aarch64/cortex_a725.S          \
 				lib/cpus/aarch64/cortex_x1.S            \
@@ -235,11 +239,12 @@
 
 #Build AArch64-only CPUs with no FVP model yet.
 ifeq (${BUILD_CPUS_WITH_NO_FVP_MODEL},1)
-	FVP_CPU_LIBS    +=	lib/cpus/aarch64/neoverse_n3.S		\
-				lib/cpus/aarch64/cortex_gelas.S		\
+	# travis/gelas need these
+	FEAT_PABANDON	:=	1
+	ERRATA_SME_POWER_DOWN := 1
+	FVP_CPU_LIBS    +=	lib/cpus/aarch64/cortex_gelas.S		\
 				lib/cpus/aarch64/nevis.S		\
 				lib/cpus/aarch64/travis.S		\
-				lib/cpus/aarch64/cortex_arcadia.S	\
 				lib/cpus/aarch64/cortex_alto.S
 endif
 
@@ -362,6 +367,19 @@
 
 FDT_SOURCES		+=	${FVP_HW_CONFIG_DTS}
 $(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS)))
+HW_CONFIG		:=	${FVP_HW_CONFIG}
+
+# Set default initrd base 128MiB offset of the default kernel address in FVP
+INITRD_BASE		?=	0x90000000
+
+# Kernel base address supports Linux kernels before v5.7
+# DTB base 1MiB before normal base kernel address in FVP (0x88000000)
+ifeq (${ARM_LINUX_KERNEL_AS_BL33},1)
+    PRELOADED_BL33_BASE ?= 0x80080000
+    ifeq (${RESET_TO_BL31},1)
+        ARM_PRELOADED_DTB_BASE ?= 0x87F00000
+    endif
+endif
 
 ifeq (${TRANSFER_LIST}, 0)
 FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
@@ -414,7 +432,6 @@
 include lib/transfer_list/transfer_list.mk
 
 ifeq ($(RESET_TO_BL31), 1)
-HW_CONFIG			:=	${FVP_HW_CONFIG}
 FW_HANDOFF_SIZE			:=	20000
 
 TRANSFER_LIST_DTB_OFFSET	:=	0x20
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
index 27ea7f7..d8d60ef 100644
--- a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -17,6 +17,8 @@
 #include "n1sdp_private.h"
 #include <platform_def.h>
 
+#define RT_OWNER 0
+
 /*
  * Platform information structure stored in SDS.
  * This structure holds information about platform's DDR
@@ -44,12 +46,16 @@
 };
 
 static struct gic600_multichip_data n1sdp_multichip_data __init = {
-	.rt_owner_base = PLAT_ARM_GICD_BASE,
-	.rt_owner = 0,
+	.base_addrs = {
+		PLAT_ARM_GICD_BASE
+	},
+	.rt_owner = RT_OWNER,
 	.chip_count = 1,
 	.chip_addrs = {
-		PLAT_ARM_GICD_BASE >> 16,
-		PLAT_ARM_GICD_BASE >> 16
+		[RT_OWNER] = {
+			PLAT_ARM_GICD_BASE >> 16,
+			PLAT_ARM_GICD_BASE >> 16
+		}
 	},
 	.spi_ids = {
 		{PLAT_ARM_GICD_BASE, 32, 511},
diff --git a/plat/arm/board/neoverse_rd/common/include/nrd3/nrd_plat_arm_def3.h b/plat/arm/board/neoverse_rd/common/include/nrd3/nrd_plat_arm_def3.h
index 7fa2b77..4936344 100644
--- a/plat/arm/board/neoverse_rd/common/include/nrd3/nrd_plat_arm_def3.h
+++ b/plat/arm/board/neoverse_rd/common/include/nrd3/nrd_plat_arm_def3.h
@@ -507,8 +507,6 @@
 #define ARM_L0_GPT_BASE			NRD_CSS_SHARED_SRAM_SIZE -	\
 					ARM_L0_GPT_SIZE
 
-#define ARM_L0_GPT_LIMIT		(ARM_L0_GPT_BASE + ARM_L0_GPT_SIZE)
-
 /*******************************************************************************
  * Arm shared RAM specifics
  ******************************************************************************/
diff --git a/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c b/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
index d3038ec..2dd8b45 100644
--- a/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
+++ b/plat/arm/board/neoverse_rd/common/nrd_bl31_setup.c
@@ -154,6 +154,13 @@
 	nrd_plat_info.config_id = plat_arm_nrd_get_config_id();
 	nrd_plat_info.multi_chip_mode = plat_arm_nrd_get_multi_chip_mode();
 
+#if RESET_TO_BL31
+#if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER)
+	/* Set the counter frequency for the generic timer */
+	write_cntfrq_el0(plat_get_syscnt_freq2());
+#endif
+#endif /* RESET_TO_BL31 */
+
 	/* Initialize generic timer */
 	generic_delay_timer_init();
 
diff --git a/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
index dcee92c..19fb796 100644
--- a/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
+++ b/plat/arm/board/neoverse_rd/common/ras/nrd_ras_cpu.c
@@ -129,8 +129,7 @@
 
 	cpu_info->ErrCtxEl3Reg[0]   = read_ctx_reg(get_el3state_ctx(ctx),
 						   CTX_ELR_EL3);
-	cpu_info->ErrCtxEl3Reg[1]   = read_ctx_reg(get_el3state_ctx(ctx),
-						   CTX_ESR_EL3);
+	cpu_info->ErrCtxEl3Reg[1]   = read_esr_el3();
 	cpu_info->ErrCtxEl3Reg[2]   = read_far_el3();
 	cpu_info->ErrCtxEl3Reg[4]   = read_mair_el3();
 	cpu_info->ErrCtxEl3Reg[5]   = read_sctlr_el3();
diff --git a/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
index ccabe22..5cbdd5f 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
@@ -11,6 +11,8 @@
 
 #include <nrd_plat.h>
 
+#define RT_OWNER 0
+
 #if defined(IMAGE_BL31)
 static const mmap_region_t rdn1edge_dynamic_mmap[] = {
 	NRD_CSS_SHARED_RAM_MMAP(1),
@@ -19,12 +21,17 @@
 };
 
 static struct gic600_multichip_data rdn1e1_multichip_data __init = {
-	.rt_owner_base = PLAT_ARM_GICD_BASE,
-	.rt_owner = 0,
+	.base_addrs = {
+		PLAT_ARM_GICD_BASE
+	},
+	.rt_owner = RT_OWNER,
 	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
-		PLAT_ARM_GICD_BASE >> 16,
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+		[RT_OWNER] = {
+			PLAT_ARM_GICD_BASE >> 16,
+			(PLAT_ARM_GICD_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+		}
 	},
 	.spi_ids = {
 		{PLAT_ARM_GICD_BASE,
diff --git a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
index b1046d6..cf820b8 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
@@ -13,6 +13,12 @@
 #include <nrd_plat.h>
 #include <rdn2_ras.h>
 
+#define RT_OWNER 0
+#define A4SID_CHIP_0	0x0
+#define A4SID_CHIP_1	0x1
+#define A4SID_CHIP_2	0x2
+#define A4SID_CHIP_3	0x3
+
 #if defined(IMAGE_BL31)
 #if (NRD_PLATFORM_VARIANT == 2)
 static const mmap_region_t rdn2mc_dynamic_mmap[] = {
@@ -33,19 +39,50 @@
 
 #if (NRD_PLATFORM_VARIANT == 2)
 static struct gic600_multichip_data rdn2mc_multichip_data __init = {
-	.rt_owner_base = PLAT_ARM_GICD_BASE,
-	.rt_owner = 0,
+	.base_addrs = {
+		PLAT_ARM_GICD_BASE,
+#if NRD_CHIP_COUNT > 1
+		PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1),
+#endif
+#if NRD_CHIP_COUNT > 2
+		PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if NRD_CHIP_COUNT > 3
+		PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+	},
+	.rt_owner = RT_OWNER,
 	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
-		PLAT_ARM_GICD_BASE >> 16,
+		{
+			A4SID_CHIP_0,
+			A4SID_CHIP_1,
+			A4SID_CHIP_2,
+			A4SID_CHIP_3
+		},
 #if NRD_CHIP_COUNT > 1
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+		{
+			A4SID_CHIP_0,
+			A4SID_CHIP_1,
+			A4SID_CHIP_2,
+			A4SID_CHIP_3
+		},
 #endif
 #if NRD_CHIP_COUNT > 2
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+		{
+			A4SID_CHIP_0,
+			A4SID_CHIP_1,
+			A4SID_CHIP_2,
+			A4SID_CHIP_3
+		},
 #endif
 #if NRD_CHIP_COUNT > 3
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+		{
+			A4SID_CHIP_0,
+			A4SID_CHIP_1,
+			A4SID_CHIP_2,
+			A4SID_CHIP_3
+		}
 #endif
 	},
 	.spi_ids = {
diff --git a/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
index 5713cb9..0a40762 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
@@ -11,6 +11,8 @@
 
 #include <nrd_plat.h>
 
+#define RT_OWNER 0
+
 #if defined(IMAGE_BL31)
 static const mmap_region_t rdv1mc_dynamic_mmap[] = {
 	NRD_CSS_SHARED_RAM_MMAP(1),
@@ -29,18 +31,25 @@
 };
 
 static struct gic600_multichip_data rdv1mc_multichip_data __init = {
-	.rt_owner_base = PLAT_ARM_GICD_BASE,
-	.rt_owner = 0,
+	.base_addrs = {
+		PLAT_ARM_GICD_BASE
+	},
+	.rt_owner = RT_OWNER,
 	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
-		PLAT_ARM_GICD_BASE >> 16,
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+		[RT_OWNER] = {
+			PLAT_ARM_GICD_BASE >> 16,
+			(PLAT_ARM_GICD_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
 #if (NRD_CHIP_COUNT > 2)
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+			(PLAT_ARM_GICD_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
 #endif
 #if (NRD_CHIP_COUNT > 3)
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+			(PLAT_ARM_GICD_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
 #endif
+		}
 	},
 	.spi_ids = {
 		{PLAT_ARM_GICD_BASE,
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/include/platform_def.h b/plat/arm/board/neoverse_rd/platform/rdv3/include/platform_def.h
index b55dbe8..0d0db77 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/include/platform_def.h
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -48,4 +48,7 @@
  */
 #define PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE	UL(0x1000)
 
+/* Protected physical address size */
+#define PLAT_ARM_PPS			(256 * SZ_1T)
+
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk b/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
index 49b7cc3..1ddd0e4 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/platform.mk
@@ -51,7 +51,7 @@
 endif
 
 # RD-V3 uses MHUv3
-PLAT_MHU_VERSION := 3
+PLAT_MHU := MHUv3
 
 include plat/arm/board/neoverse_rd/common/nrd-common.mk
 include drivers/arm/rse/rse_comms.mk
@@ -144,7 +144,7 @@
 			${RDV3_BASE}/fdts/${PLAT}_nt_fw_config.dts
 
 ifeq (${SPMD_SPM_AT_SEL2}, 1)
-BL32_CONFIG_DTS                :=      ${RDV3_BASE}/fdts/${PLAT}_spmc_sp_manifest.dts
+BL32_CONFIG_DTS        :=      ${RDV3_BASE}/fdts/${PLAT}_spmc_sp_manifest.dts
 FDT_SOURCES            +=      ${BL32_CONFIG_DTS}
 TOS_FW_CONFIG          :=      ${BUILD_PLAT}/fdts/$(notdir $(basename ${BL32_CONFIG_DTS})).dtb
 endif
@@ -169,4 +169,14 @@
 
 # FEAT_SVE related flags
 override SVE_VECTOR_LEN		:= 128
-override CTX_INCLUDE_SVE_REGS	:= 1
+
+override CTX_INCLUDE_SVE_REGS   := 1
+
+# Enabling CTX_INCLUDE_SVE_REGS along with SPMD_SPM_AT_SEL2=1 is a invalid
+# combination and will lead to build failure, use them only when SPMD_SPM_AT_SEL2=0
+# In this combination its SPMC responsbility to save SVE regs.
+ifeq (${SPD},spmd)
+ifeq (${SPMD_SPM_AT_SEL2},1)
+override CTX_INCLUDE_SVE_REGS	:= 0
+endif
+endif
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
index a5d687e..e32e761 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
@@ -15,6 +15,15 @@
 #include <nrd_variant.h>
 #include <rdv3_rse_comms.h>
 
+#define RT_OWNER 0
+
+/*
+ * Base addr of the frame that allocated by the platform
+ * intended for remote gic to local gic interrupt
+ * message communication
+ */
+#define NRD_RGIC2LGIC_MESSREG_HNI_BASE		UL(0x5FFF0000)
+
 #if (NRD_PLATFORM_VARIANT == 2)
 static const mmap_region_t rdv3mc_dynamic_mmap[] = {
 #if NRD_CHIP_COUNT > 1
@@ -32,19 +41,62 @@
 };
 
 static struct gic600_multichip_data rdv3mc_multichip_data __init = {
-	.rt_owner_base = PLAT_ARM_GICD_BASE,
-	.rt_owner = 0,
+	.base_addrs = {
+		PLAT_ARM_GICD_BASE,
+#if NRD_CHIP_COUNT > 1
+		PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1),
+#endif
+#if NRD_CHIP_COUNT > 2
+		PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if NRD_CHIP_COUNT > 3
+		PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+	},
+	.rt_owner = RT_OWNER,
 	.chip_count = NRD_CHIP_COUNT,
 	.chip_addrs = {
-		PLAT_ARM_GICD_BASE >> 16,
+		{
+			NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+		},
 #if NRD_CHIP_COUNT > 1
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+		{
+			NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+		},
 #endif
 #if NRD_CHIP_COUNT > 2
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+		{
+			NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+		},
 #endif
 #if NRD_CHIP_COUNT > 3
-		(PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+		{
+			NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+			(NRD_RGIC2LGIC_MESSREG_HNI_BASE
+				+ NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+		}
 #endif
 	},
 	.spi_ids = {
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
index 3ef9681..364bce1 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_common.c
@@ -6,6 +6,7 @@
 
 #include <common/debug.h>
 #include <drivers/arm/gic600_multichip.h>
+#include <drivers/arm/mhu.h>
 #include <drivers/arm/rse_comms.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
@@ -64,7 +65,7 @@
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest)
 {
 	uint64_t checksum, num_banks, num_consoles;
-	struct ns_dram_bank *bank_ptr;
+	struct memory_bank *bank_ptr;
 	struct console_info *console_ptr;
 
 	assert(manifest != NULL);
@@ -129,7 +130,7 @@
 	 * +--------+----------------+--------------+
 	 */
 
-	bank_ptr = (struct ns_dram_bank *)
+	bank_ptr = (struct memory_bank *)
 			(((uintptr_t)manifest) + sizeof(*manifest));
 	console_ptr = (struct console_info *)
 			((uintptr_t)bank_ptr + (num_banks * sizeof(*bank_ptr)));
@@ -141,7 +142,7 @@
 	assert((sizeof(struct rmm_manifest) +
 		(sizeof(struct console_info) *
 		manifest->plat_console.num_consoles) +
-		(sizeof(struct ns_dram_bank) * manifest->plat_dram.num_banks))
+		(sizeof(struct memory_bank) * manifest->plat_dram.num_banks))
 		<= ARM_EL3_RMM_SHARED_SIZE);
 
 	/* Calculate checksum of plat_dram structure */
@@ -156,7 +157,7 @@
 
 	/* Update checksum */
 	checksum += checksum_calc((uint64_t *)bank_ptr,
-		sizeof(struct ns_dram_bank) * num_banks);
+		sizeof(struct memory_bank) * num_banks);
 
 	/* Checksum must be 0 */
 	manifest->plat_dram.checksum = ~checksum + 1UL;
@@ -188,15 +189,15 @@
 
 int plat_rse_comms_init(void)
 {
-	uintptr_t snd_base, rcv_base;
+	struct mhu_addr mhu_addresses;
 
 	/* Get sender and receiver frames for AP-RSE communication */
-	mhu_v3_get_secure_device_base(&snd_base, true);
-	mhu_v3_get_secure_device_base(&rcv_base, false);
+	mhu_v3_get_secure_device_base(&mhu_addresses.sender_base, true);
+	mhu_v3_get_secure_device_base(&mhu_addresses.receiver_base, false);
 
 	VERBOSE("Initializing the rse_comms now\n");
 	/* Initialize the communication channel between AP and RSE */
-	return rse_comms_init(snd_base, rcv_base);
+	return rse_mbx_init(&mhu_addresses);
 }
 
 int plat_spmd_handle_group0_interrupt(uint32_t intid)
diff --git a/plat/arm/board/tc/include/tc_rse_comms.h b/plat/arm/board/tc/include/tc_rse_comms.h
new file mode 100644
index 0000000..dc2000e
--- /dev/null
+++ b/plat/arm/board/tc/include/tc_rse_comms.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TC_RSE_COMMS_H
+#define TC_RSE_COMMS_H
+
+int plat_rse_comms_init(void);
+
+#endif /* TC_RSE_COMMS_H */
diff --git a/plat/arm/board/tc/nv_counter_test.c b/plat/arm/board/tc/nv_counter_test.c
index 9025569..94cba22 100644
--- a/plat/arm/board/tc/nv_counter_test.c
+++ b/plat/arm/board/tc/nv_counter_test.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,11 +7,11 @@
 #include <stdint.h>
 #include <stdio.h>
 
-#include <drivers/arm/rse_comms.h>
 #include <plat/common/platform.h>
 #include "rse_platform_api.h"
 
 #include <platform_def.h>
+#include <tc_rse_comms.h>
 
 int nv_counter_test(void)
 {
@@ -20,7 +20,7 @@
 	uint32_t new_val;
 	uint32_t id;
 
-	status = rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE, PLAT_RSE_AP_RCV_MHU_BASE);
+	status = plat_rse_comms_init();
 	if (status != PSA_SUCCESS) {
 		printf("Failed to initialize RSE communication channel - psa_status = %d\n", status);
 		return -1;
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 21d7122..a056bc2 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -32,10 +32,8 @@
 ENABLE_TRBE_FOR_NS		:=	1
 ENABLE_SYS_REG_TRACE_FOR_NS	:=	1
 ENABLE_FEAT_AMU			:=	1
-ENABLE_AMU_FCONF		:=	1
 ENABLE_AMU_AUXILIARY_COUNTERS	:=	1
 ENABLE_MPMM			:=	1
-ENABLE_MPMM_FCONF		:=	1
 ENABLE_FEAT_MTE2		:=	2
 ENABLE_SPE_FOR_NS		:=	3
 ENABLE_FEAT_TCR2		:=	3
@@ -112,9 +110,9 @@
 
 # Specify MHU type based on platform
 ifneq ($(filter ${TARGET_PLATFORM}, 2),)
-	PLAT_MHU_VERSION	:= 2
+	PLAT_MHU		:= MHUv2
 else
-	PLAT_MHU_VERSION	:= 3
+	PLAT_MHU		:= MHUv3
 endif
 
 # Include GICv3 driver files
@@ -157,6 +155,9 @@
 
 # CPU libraries for TARGET_PLATFORM=4
 ifeq (${TARGET_PLATFORM}, 4)
+FEAT_PABANDON	:=	1
+# prevent CME related wakups
+ERRATA_SME_POWER_DOWN := 1
 TC_CPU_SOURCES	+=	lib/cpus/aarch64/cortex_gelas.S \
 			lib/cpus/aarch64/nevis.S \
 			lib/cpus/aarch64/travis.S
@@ -246,9 +247,12 @@
 $(info Including rse_comms.mk)
 include drivers/arm/rse/rse_comms.mk
 
-BL1_SOURCES	+=	${RSE_COMMS_SOURCES}
-BL2_SOURCES	+=	${RSE_COMMS_SOURCES}
+BL1_SOURCES	+=	${RSE_COMMS_SOURCES} \
+			plat/arm/board/tc/tc_rse_comms.c
+BL2_SOURCES	+=	${RSE_COMMS_SOURCES} \
+			plat/arm/board/tc/tc_rse_comms.c
 BL31_SOURCES	+=	${RSE_COMMS_SOURCES} \
+			plat/arm/board/tc/tc_rse_comms.c \
 			lib/psa/rse_platform.c
 
 # Include Measured Boot makefile before any Crypto library makefile.
diff --git a/plat/arm/board/tc/platform_test.mk b/plat/arm/board/tc/platform_test.mk
index 2ce6648..4afa30f 100644
--- a/plat/arm/board/tc/platform_test.mk
+++ b/plat/arm/board/tc/platform_test.mk
@@ -1,4 +1,4 @@
-# Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -9,7 +9,8 @@
     include drivers/arm/rse/rse_comms.mk
 
     # Test code.
-    BL31_SOURCES	+=	plat/arm/board/tc/nv_counter_test.c
+    BL31_SOURCES	+=	plat/arm/board/tc/nv_counter_test.c \
+				plat/arm/board/tc/tc_rse_comms.c
 
     # Code under testing.
     BL31_SOURCES	+=	lib/psa/rse_platform.c \
@@ -22,7 +23,8 @@
     include drivers/arm/rse/rse_comms.mk
 
     # Test code.
-    BL31_SOURCES	+=	plat/arm/board/tc/rotpk_test.c
+    BL31_SOURCES	+=	plat/arm/board/tc/rotpk_test.c \
+				plat/arm/board/tc/tc_rse_comms.c
 
     # Code under testing.
     BL31_SOURCES	+=	lib/psa/rse_platform.c \
@@ -75,6 +77,7 @@
 				${TC_BASE}/rse_ap_tests.c			\
 				${TC_BASE}/rse_ap_testsuites.c			\
 				${TC_BASE}/rse_ap_test_stubs.c			\
+				${TC_BASE}/tc_rse_comms.c			\
 				$(TF_M_TESTS_PATH)/tests_reg/test/framework/test_framework.c \
 				$(MEASURED_BOOT_TESTS_PATH)/measured_boot_common.c \
 				$(MEASURED_BOOT_TESTS_PATH)/measured_boot_tests_common.c \
diff --git a/plat/arm/board/tc/rotpk_test.c b/plat/arm/board/tc/rotpk_test.c
index 2178f69..3d6c95d 100644
--- a/plat/arm/board/tc/rotpk_test.c
+++ b/plat/arm/board/tc/rotpk_test.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,10 +7,10 @@
 #include <stdint.h>
 #include <stdio.h>
 
-#include <drivers/arm/rse_comms.h>
 #include <plat/common/platform.h>
 #include <rse_platform_api.h>
 #include <tc_plat.h>
+#include <tc_rse_comms.h>
 
 static void print_hex(const char *key_id_name, size_t key_size, const uint8_t *key_buf)
 {
@@ -33,9 +33,10 @@
 	       {.key_id = RSE_BUILTIN_KEY_ID_HOST_CCA_ROTPK,  .key_id_name = "CCA-ROTPK"}
 	};
 
-	status = rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE, PLAT_RSE_AP_RCV_MHU_BASE);
+	status = plat_rse_comms_init();
 	if (status != PSA_SUCCESS) {
-		printf("Failed to initialize RSE communication channel - psa_status = %d\n", status);
+		printf("Failed to initialize RSE communication channel - psa_status = %d\n",
+		       status);
 		return -1;
 	}
 
@@ -43,7 +44,8 @@
 		status = rse_platform_key_read(key_ids[i].key_id, key_buf,
 			       sizeof(key_buf), &key_size);
 		if (status != PSA_SUCCESS) {
-			printf("Failed to retrieve %s - psa_status = %d\n", key_ids[i].key_id_name, status);
+			printf("Failed to retrieve %s - psa_status = %d\n", key_ids[i].key_id_name,
+			       status);
 			return -1;
 		}
 		print_hex(key_ids[i].key_id_name, key_size, key_buf);
diff --git a/plat/arm/board/tc/rse_ap_tests.c b/plat/arm/board/tc/rse_ap_tests.c
index 3ca628a..f8ee1c5 100644
--- a/plat/arm/board/tc/rse_ap_tests.c
+++ b/plat/arm/board/tc/rse_ap_tests.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Ltd. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,9 +10,9 @@
 #include <mbedtls_common.h>
 #include <plat/common/platform.h>
 #include <psa/crypto.h>
-#include <rse_comms.h>
 
 #include "rse_ap_testsuites.h"
+#include <tc_rse_comms.h>
 
 static struct test_suite_t test_suites[] = {
 	{.freg = register_testsuite_delegated_attest},
@@ -32,7 +32,7 @@
 	size_t i;
 
 	/* Initialize test environment. */
-	rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE, PLAT_RSE_AP_RCV_MHU_BASE);
+	plat_rse_comms_init();
 	mbedtls_init();
 	status = psa_crypto_init();
 	if (status != PSA_SUCCESS) {
diff --git a/plat/arm/board/tc/tc_bl1_dpe.c b/plat/arm/board/tc/tc_bl1_dpe.c
index de5702a..62e86f9 100644
--- a/plat/arm/board/tc/tc_bl1_dpe.c
+++ b/plat/arm/board/tc/tc_bl1_dpe.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,7 +8,6 @@
 
 #include <common/debug.h>
 #include <drivers/arm/css/sds.h>
-#include <drivers/arm/rse_comms.h>
 #include <drivers/delay_timer.h>
 #include <drivers/generic_delay_timer.h>
 #include <drivers/measured_boot/metadata.h>
@@ -19,6 +18,7 @@
 #include <tools_share/zero_oid.h>
 
 #include "tc_dpe.h"
+#include <tc_rse_comms.h>
 
 struct dpe_metadata tc_dpe_metadata[] = {
 	{
@@ -122,8 +122,7 @@
 void bl1_plat_mboot_init(void)
 {
 	/* Initialize the communication channel between AP and RSE */
-	(void)rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE,
-			     PLAT_RSE_AP_RCV_MHU_BASE);
+	(void)plat_rse_comms_init();
 
 	dpe_init(tc_dpe_metadata);
 }
diff --git a/plat/arm/board/tc/tc_bl1_measured_boot.c b/plat/arm/board/tc/tc_bl1_measured_boot.c
index 28a1e31..b5617cc 100644
--- a/plat/arm/board/tc/tc_bl1_measured_boot.c
+++ b/plat/arm/board/tc/tc_bl1_measured_boot.c
@@ -1,18 +1,18 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <stdint.h>
 
-#include <drivers/arm/rse_comms.h>
 #include <drivers/measured_boot/metadata.h>
 #include <drivers/measured_boot/rse/rse_measured_boot.h>
 #include <tools_share/zero_oid.h>
 
 #include <plat/arm/common/plat_arm.h>
 #include <platform_def.h>
+#include <tc_rse_comms.h>
 
 /* Table with platform specific image IDs and metadata. Intentionally not a
  * const struct, some members might set by bootloaders during trusted boot.
@@ -47,8 +47,7 @@
 void bl1_plat_mboot_init(void)
 {
 	/* Initialize the communication channel between AP and RSE */
-	(void)rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE,
-			     PLAT_RSE_AP_RCV_MHU_BASE);
+	(void)plat_rse_comms_init();
 
 	rse_measured_boot_init(tc_rse_mboot_metadata);
 }
diff --git a/plat/arm/board/tc/tc_bl2_dpe.c b/plat/arm/board/tc/tc_bl2_dpe.c
index 94fddd4..e2c3a38 100644
--- a/plat/arm/board/tc/tc_bl2_dpe.c
+++ b/plat/arm/board/tc/tc_bl2_dpe.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,7 +7,6 @@
 #include <stdint.h>
 
 #include <common/debug.h>
-#include <drivers/arm/rse_comms.h>
 #include <drivers/measured_boot/metadata.h>
 #include <drivers/measured_boot/rse/dice_prot_env.h>
 #include <plat/arm/common/plat_arm.h>
@@ -16,6 +15,7 @@
 #include <tools_share/tbbr_oid.h>
 
 #include "tc_dpe.h"
+#include <tc_rse_comms.h>
 
 /*
  * The content and the values of this array depends on:
@@ -254,8 +254,7 @@
 #endif
 
 	/* Initialize the communication channel between AP and RSE */
-	(void)rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE,
-			     PLAT_RSE_AP_RCV_MHU_BASE);
+	(void)plat_rse_comms_init();
 
 	dpe_init(tc_dpe_metadata);
 }
diff --git a/plat/arm/board/tc/tc_bl2_measured_boot.c b/plat/arm/board/tc/tc_bl2_measured_boot.c
index 3957c90..8238b8b 100644
--- a/plat/arm/board/tc/tc_bl2_measured_boot.c
+++ b/plat/arm/board/tc/tc_bl2_measured_boot.c
@@ -1,18 +1,18 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <stdint.h>
 
-#include <drivers/arm/rse_comms.h>
 #include <drivers/measured_boot/metadata.h>
 #include <drivers/measured_boot/rse/rse_measured_boot.h>
 #include <tools_share/tbbr_oid.h>
 
 #include <plat/common/common_def.h>
 #include <platform_def.h>
+#include <tc_rse_comms.h>
 
 /* TC specific table with image IDs and metadata. Intentionally not a
  * const struct, some members might set by bootloaders during trusted boot.
@@ -53,8 +53,7 @@
 void bl2_plat_mboot_init(void)
 {
 	/* Initialize the communication channel between AP and RSE */
-	(void)rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE,
-			     PLAT_RSE_AP_RCV_MHU_BASE);
+	(void)plat_rse_comms_init();
 
 	rse_measured_boot_init(tc_rse_mboot_metadata);
 }
diff --git a/plat/arm/board/tc/tc_bl31_setup.c b/plat/arm/board/tc/tc_bl31_setup.c
index 4e346ab..5d19aeb 100644
--- a/plat/arm/board/tc/tc_bl31_setup.c
+++ b/plat/arm/board/tc/tc_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,8 +27,8 @@
 #endif /* PLATFORM_TEST_TFM_TESTSUITE */
 #include <psa/error.h>
 
-#include <drivers/arm/rse_comms.h>
 #include <plat/common/platform.h>
+#include <tc_rse_comms.h>
 
 #ifdef PLATFORM_TEST_TFM_TESTSUITE
 /*
@@ -72,6 +72,18 @@
 };
 #endif
 
+/* the bottom 3 AMU group 1 counters */
+#define MPMM_GEARS ((1 << 0) | (1 << 1) | (1 << 2))
+
+uint16_t plat_amu_aux_enables[PLATFORM_CORE_COUNT] = {
+	MPMM_GEARS, MPMM_GEARS, MPMM_GEARS, MPMM_GEARS,
+	MPMM_GEARS, MPMM_GEARS, MPMM_GEARS, MPMM_GEARS,
+#if PLATFORM_CORE_COUNT == 14
+	MPMM_GEARS, MPMM_GEARS, MPMM_GEARS, MPMM_GEARS,
+	MPMM_GEARS, MPMM_GEARS
+#endif
+};
+
 #if (TARGET_PLATFORM == 3) || (TARGET_PLATFORM == 4)
 static void enable_ns_mcn_pmu(void)
 {
@@ -126,7 +138,7 @@
 #endif
 
 	/* Initialise RSE communication channel */
-	status = rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE, PLAT_RSE_AP_RCV_MHU_BASE);
+	status = plat_rse_comms_init();
 	if (status != PSA_SUCCESS) {
 		ERROR("Failed to initialize RSE communication channel - psa_status = %d\n", status);
 	}
diff --git a/plat/arm/board/tc/tc_rse_comms.c b/plat/arm/board/tc/tc_rse_comms.c
new file mode 100644
index 0000000..cbb0336
--- /dev/null
+++ b/plat/arm/board/tc/tc_rse_comms.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022-2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/mhu.h>
+#include <drivers/arm/rse_comms.h>
+#include <platform_def.h>
+#include <tc_rse_comms.h>
+
+static const struct mhu_addr mhu_addresses = {
+	PLAT_RSE_AP_SND_MHU_BASE,
+	PLAT_RSE_AP_RCV_MHU_BASE
+};
+
+int plat_rse_comms_init(void)
+{
+	VERBOSE("Initializing the rse_comms now\n");
+	/* Initialize the communication channel between AP and RSE */
+	return rse_mbx_init(&mhu_addresses);
+}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index ce1545f..0503acf 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -34,9 +34,31 @@
  */
 static entry_point_info_t bl32_image_ep_info;
 static entry_point_info_t bl33_image_ep_info;
+
 #if ENABLE_RME
 static entry_point_info_t rmm_image_ep_info;
+#if (RME_GPT_BITLOCK_BLOCK == 0)
+#define BITLOCK_BASE	UL(0)
+#define BITLOCK_SIZE	UL(0)
+#else
+/*
+ * Number of bitlock_t entries in bitlocks array for PLAT_ARM_PPS
+ * with RME_GPT_BITLOCK_BLOCK * 512MB per bitlock.
+ */
+#if (PLAT_ARM_PPS > (RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8)))
+#define BITLOCKS_NUM	(PLAT_ARM_PPS) /	\
+			(RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8))
+#else
+#define BITLOCKS_NUM	U(1)
 #endif
+/*
+ * Bitlocks array
+ */
+static bitlock_t gpt_bitlock[BITLOCKS_NUM];
+#define BITLOCK_BASE	(uintptr_t)gpt_bitlock
+#define BITLOCK_SIZE	sizeof(gpt_bitlock)
+#endif /* RME_GPT_BITLOCK_BLOCK */
+#endif /* ENABLE_RME */
 
 #if !RESET_TO_BL31
 /*
@@ -551,7 +573,7 @@
 	 * stage, so there is no need to provide any PAS here. This function
 	 * sets up pointers to those tables.
 	 */
-	if (gpt_runtime_init() < 0) {
+	if (gpt_runtime_init(BITLOCK_BASE, BITLOCK_SIZE) < 0) {
 		ERROR("gpt_runtime_init() failed!\n");
 		panic();
 	}
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 580ef5f..6d59bae 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -108,9 +108,6 @@
       $(error ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_SP_MIN=1.)
     endif
   endif
-  ifndef PRELOADED_BL33_BASE
-    $(error PRELOADED_BL33_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.)
-  endif
   ifeq (${RESET_TO_BL31},1)
     ifndef ARM_PRELOADED_DTB_BASE
       $(error ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used with RESET_TO_BL31.)
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
index 498dedf..3e6c9f2 100644
--- a/plat/arm/common/arm_pm.c
+++ b/plat/arm/common/arm_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -56,6 +56,10 @@
 	if (psci_get_pstate_id(power_state) != 0U)
 		return PSCI_E_INVALID_PARAMS;
 
+#if PSCI_OS_INIT_MODE
+	req_state->last_at_pwrlvl = psci_get_pstate_pwrlvl(power_state);
+#endif /* __PSCI_OS_INIT_MODE__ */
+
 	return PSCI_E_SUCCESS;
 }
 
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index bfb6906..f8bc542 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -217,12 +217,12 @@
 /*******************************************************************************
  * Handlers to shutdown/reboot the system
  ******************************************************************************/
-void __dead2 css_system_off(void)
+void css_system_off(void)
 {
 	css_scp_sys_shutdown();
 }
 
-void __dead2 css_system_reset(void)
+void css_system_reset(void)
 {
 	css_scp_sys_reboot();
 }
@@ -364,11 +364,9 @@
 	plat_arm_gic_cpuif_disable();
 	plat_arm_gic_redistif_off();
 
-	psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
+	psci_pwrdown_cpu_start(PLAT_MAX_PWR_LVL);
 
-	dmbsy();
-
-	wfi();
+	psci_pwrdown_cpu_end_terminal();
 	return 0;
 }
 
diff --git a/plat/common/plat_psci_common.c b/plat/common/plat_psci_common.c
index c32e59f..4cea0b9 100644
--- a/plat/common/plat_psci_common.c
+++ b/plat/common/plat_psci_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -30,6 +30,12 @@
 #define PSCI_STAT_ID_EXIT_LOW_PWR		1
 #define PSCI_STAT_TOTAL_IDS			2
 
+#if HW_ASSISTED_COHERENCY
+#define CACHE_MAINTENANCE_ATTR	PMF_NO_CACHE_MAINT
+#else
+#define CACHE_MAINTENANCE_ATTR	PMF_CACHE_MAINT
+#endif
+
 PMF_DECLARE_CAPTURE_TIMESTAMP(psci_svc)
 PMF_DECLARE_GET_TIMESTAMP(psci_svc)
 PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS,
@@ -70,7 +76,7 @@
 {
 	assert(state_info != NULL);
 	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
-		PMF_CACHE_MAINT);
+		CACHE_MAINTENANCE_ATTR);
 }
 
 /*
@@ -82,7 +88,7 @@
 {
 	assert(state_info != NULL);
 	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
-		PMF_CACHE_MAINT);
+		CACHE_MAINTENANCE_ATTR);
 }
 
 /*
@@ -93,22 +99,27 @@
 	const psci_power_state_t *state_info,
 	unsigned int last_cpu_idx)
 {
-	plat_local_state_t state;
 	unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
 	unsigned int pmf_flags;
 
 	assert((lvl >= PSCI_CPU_PWR_LVL) && (lvl <= PLAT_MAX_PWR_LVL));
-	assert(state_info != NULL);
 	assert(last_cpu_idx <= PLATFORM_CORE_COUNT);
 
 	if (lvl == PSCI_CPU_PWR_LVL)
 		assert(last_cpu_idx == plat_my_core_pos());
 
+#if HW_ASSISTED_COHERENCY
+	/* HW coherency allows for the capture and access to happen with caches
+	 * ON. So these timestamps don't need cache maintenance */
+	pmf_flags = PMF_NO_CACHE_MAINT;
+#else
 	/*
 	 * If power down is requested, then timestamp capture will
 	 * be with caches OFF.  Hence we have to do cache maintenance
 	 * when reading the timestamp.
 	 */
+	plat_local_state_t state;
+	assert(state_info != NULL);
 	state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
 	if (is_local_state_off(state) != 0) {
 		pmf_flags = PMF_CACHE_MAINT;
@@ -116,6 +127,7 @@
 		assert(is_local_state_retn(state) == 1);
 		pmf_flags = PMF_NO_CACHE_MAINT;
 	}
+#endif
 
 	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
 		PSCI_STAT_ID_ENTER_LOW_PWR,
diff --git a/plat/imx/common/include/imx_sip_svc.h b/plat/imx/common/include/imx_sip_svc.h
index 404a829..ecb43c3 100644
--- a/plat/imx/common/include/imx_sip_svc.h
+++ b/plat/imx/common/include/imx_sip_svc.h
@@ -72,6 +72,8 @@
 	SMC_RET1(handle, SMC_UNK);
 }
 #endif
+int imx_hab_handler(uint32_t smc_fid, u_register_t x1,
+	u_register_t x2, u_register_t x3, u_register_t x4);
 #endif
 #if defined(PLAT_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
 int dram_dvfs_handler(uint32_t smc_fid, void *handle,
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_psci.c b/plat/imx/imx8m/imx8mm/imx8mm_psci.c
index 815d3a2..766c7b3 100644
--- a/plat/imx/imx8m/imx8mm/imx8mm_psci.c
+++ b/plat/imx/imx8m/imx8mm/imx8mm_psci.c
@@ -25,7 +25,7 @@
 	.cpu_standby = imx_cpu_standby,
 	.pwr_domain_suspend = imx_domain_suspend,
 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
 	.system_reset = imx_system_reset,
 	.system_reset2 = imx_system_reset2,
diff --git a/plat/imx/imx8m/imx8mn/imx8mn_psci.c b/plat/imx/imx8m/imx8mn/imx8mn_psci.c
index f541fc1..4947d66 100644
--- a/plat/imx/imx8m/imx8mn/imx8mn_psci.c
+++ b/plat/imx/imx8m/imx8mn/imx8mn_psci.c
@@ -25,7 +25,7 @@
 	.cpu_standby = imx_cpu_standby,
 	.pwr_domain_suspend = imx_domain_suspend,
 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
 	.system_reset = imx_system_reset,
 	.system_off = imx_system_off,
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_psci.c b/plat/imx/imx8m/imx8mp/imx8mp_psci.c
index bc7b246..0a8c351 100644
--- a/plat/imx/imx8m/imx8mp/imx8mp_psci.c
+++ b/plat/imx/imx8m/imx8mp/imx8mp_psci.c
@@ -25,7 +25,7 @@
 	.cpu_standby = imx_cpu_standby,
 	.pwr_domain_suspend = imx_domain_suspend,
 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
 	.system_reset = imx_system_reset,
 	.system_off = imx_system_off,
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
index 70c2def..fdaf9fd 100644
--- a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
@@ -52,6 +52,8 @@
 	MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), /* GIC map */
 	MAP_REGION_FLAT(IMX_DDRPHY_BASE, IMX_DDR_IPS_SIZE, MT_DEVICE | MT_RW), /* DDRMIX map */
 	MAP_REGION_FLAT(IMX_DRAM_BASE, IMX_DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS),
+	MAP_REGION_FLAT(IMX_CAAM_RAM_BASE, IMX_CAAM_RAM_SIZE, MT_MEMORY | MT_RW), /* CAMM RAM */
+	MAP_REGION_FLAT(IMX_NS_OCRAM_BASE, IMX_NS_OCRAM_SIZE, MT_MEMORY | MT_RW), /* NS OCRAM */
 	{0},
 };
 
@@ -207,13 +209,19 @@
 				MT_MEMORY | MT_RW | MT_SECURE),
 		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
 				MT_MEMORY | MT_RO | MT_SECURE),
+#if SEPARATE_NOBITS_REGION
+		MAP_REGION_FLAT(BL_NOBITS_BASE, BL_NOBITS_END - BL_NOBITS_BASE,
+				MT_RW_DATA | MT_SECURE),
+#endif
 #if USE_COHERENT_MEM
 		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
 				BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
 				MT_DEVICE | MT_RW | MT_SECURE),
 #endif
+#if defined(SPD_opteed) || defined(SPD_trusty)
 		/* Map TEE memory */
 		MAP_REGION_FLAT(BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW),
+#endif
 		{0},
 	};
 
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_psci.c b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
index 3375ce7..c023b55 100644
--- a/plat/imx/imx8m/imx8mq/imx8mq_psci.c
+++ b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
@@ -137,7 +137,7 @@
 	.cpu_standby = imx_cpu_standby,
 	.pwr_domain_suspend = imx_domain_suspend,
 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
 	.system_reset = imx_system_reset,
 	.system_reset2 = imx_system_reset2,
diff --git a/plat/imx/imx8m/imx8mq/include/platform_def.h b/plat/imx/imx8m/imx8mq/include/platform_def.h
index 61c0e8e..34bd77e 100644
--- a/plat/imx/imx8m/imx8mq/include/platform_def.h
+++ b/plat/imx/imx8m/imx8mq/include/platform_def.h
@@ -10,7 +10,7 @@
 #define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
 #define PLATFORM_LINKER_ARCH		aarch64
 
-#define PLATFORM_STACK_SIZE		0x800
+#define PLATFORM_STACK_SIZE		0xb00
 #define CACHE_WRITEBACK_GRANULE		64
 
 #define PLAT_PRIMARY_CPU		U(0x0)
@@ -37,6 +37,12 @@
 #define BL31_SIZE			SZ_64K
 #define BL31_LIMIT			(BL31_BASE + BL31_SIZE)
 
+#define OCRAM_S_BASE			U(0x180000)
+#define OCRAM_S_SIZE			SZ_32K
+#define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
+#define BL31_NOBITS_BASE		OCRAM_S_BASE
+#define BL31_NOBITS_LIMIT		(BL31_NOBITS_BASE + SZ_32K)
+
 /* non-secure uboot base */
 #ifndef PLAT_NS_IMAGE_OFFSET
 #define PLAT_NS_IMAGE_OFFSET		U(0x40200000)
@@ -54,7 +60,7 @@
 #define MAX_XLAT_TABLES			5
 #define MAX_MMAP_REGIONS		15
 #else
-#define MAX_XLAT_TABLES			4
+#define MAX_XLAT_TABLES			3
 #define MAX_MMAP_REGIONS		14
 #endif
 
@@ -93,7 +99,10 @@
 #define IMX_DDR_IPS_SIZE		U(0x1800000)
 #define IMX_DRAM_BASE			U(0x40000000)
 #define IMX_DRAM_SIZE			U(0xc0000000)
-
+#define IMX_NS_OCRAM_BASE		U(0x900000)
+#define IMX_NS_OCRAM_SIZE		U(0x20000)
+#define IMX_CAAM_RAM_BASE		U(0x100000)
+#define IMX_CAAM_RAM_SIZE		U(0x10000)
 #define IMX_ROM_BASE			U(0x00000000)
 #define IMX_ROM_SIZE			U(0x20000)
 
@@ -141,10 +150,6 @@
 #define GPR_TZASC_EN			BIT(0)
 #define GPR_TZASC_EN_LOCK		BIT(16)
 
-#define OCRAM_S_BASE			U(0x00180000)
-#define OCRAM_S_SIZE			U(0x8000)
-#define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
-
 #define COUNTER_FREQUENCY		8333333 /* 25MHz / 3 */
 
 #define IMX_WDOG_B_RESET
diff --git a/plat/imx/imx8m/imx8mq/platform.mk b/plat/imx/imx8m/imx8mq/platform.mk
index 73179dd..76fc071 100644
--- a/plat/imx/imx8m/imx8mq/platform.mk
+++ b/plat/imx/imx8m/imx8mq/platform.mk
@@ -29,6 +29,7 @@
 				plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c	\
 				plat/imx/imx8m/imx8mq/imx8mq_psci.c		\
 				plat/imx/imx8m/gpc_common.c			\
+				plat/imx/imx8m/imx_hab.c			\
 				plat/imx/imx8m/imx_aipstz.c			\
 				plat/imx/imx8m/imx8m_caam.c			\
 				plat/imx/imx8m/imx8m_ccm.c			\
@@ -63,6 +64,8 @@
 BL31_SOURCES		+=	${IMX_DRAM_SOURCES}
 endif
 
+SEPARATE_NOBITS_REGION  :=        1
+
 ifneq (${PRELOADED_BL33_BASE},)
 $(eval $(call add_define_val,PLAT_NS_IMAGE_OFFSET,${PRELOADED_BL33_BASE}))
 endif
diff --git a/plat/imx/imx8ulp/imx8ulp_psci.c b/plat/imx/imx8ulp/imx8ulp_psci.c
index 628acea..59af8be 100644
--- a/plat/imx/imx8ulp/imx8ulp_psci.c
+++ b/plat/imx/imx8ulp/imx8ulp_psci.c
@@ -538,7 +538,7 @@
 	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
 	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
 	.validate_power_state = imx_validate_power_state,
-	.pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = imx8ulp_pwr_domain_pwr_down_wfi,
 };
 
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
diff --git a/plat/intel/soc/agilex5/bl2_plat_setup.c b/plat/intel/soc/agilex5/bl2_plat_setup.c
index fe5dc6e..f4010f9 100644
--- a/plat/intel/soc/agilex5/bl2_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl2_plat_setup.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -31,6 +31,8 @@
 #include "nand/nand.h"
 #include "qspi/cadence_qspi.h"
 #include "sdmmc/sdmmc.h"
+/* TODO: DTB not available */
+// #include "socfpga_dt.h"
 #include "socfpga_emac.h"
 #include "socfpga_f2sdram_manager.h"
 #include "socfpga_handoff.h"
@@ -138,6 +140,12 @@
 	/* DDR and IOSSM driver init */
 	agilex5_ddr_init(&reverse_handoff_ptr);
 
+	/* TODO: DTB not available */
+	// if (socfpga_dt_open_and_check(SOCFPGA_DTB_BASE, DT_COMPATIBLE_STR) < 0) {
+		// ERROR("SOCFPGA: Failed to open device tree\n");
+		// panic();
+	// }
+
 	if (combo_phy_init(&reverse_handoff_ptr) != 0) {
 		ERROR("SOCFPGA: Combo Phy initialization failed\n");
 	}
@@ -165,13 +173,13 @@
 
 	switch (boot_source) {
 	case BOOT_SOURCE_SDMMC:
-		NOTICE("SDMMC boot\n");
+		NOTICE("SOCFPGA: SDMMC boot\n");
 		cdns_mmc_init(&params, &mmc_info);
 		socfpga_io_setup(boot_source, PLAT_SDMMC_DATA_BASE);
 		break;
 
 	case BOOT_SOURCE_QSPI:
-		NOTICE("QSPI boot\n");
+		NOTICE("SOCFPGA: QSPI boot\n");
 		cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL,
 			QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS,
 			QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0);
@@ -182,13 +190,13 @@
 		break;
 
 	case BOOT_SOURCE_NAND:
-		NOTICE("NAND boot\n");
+		NOTICE("SOCFPGA: SOCFPGA: NAND boot\n");
 		nand_init(&reverse_handoff_ptr);
 		socfpga_io_setup(boot_source, PLAT_NAND_DATA_BASE);
 		break;
 
 	default:
-		ERROR("Unsupported boot source\n");
+		ERROR("SOCFPGA: Unsupported boot source\n");
 		panic();
 		break;
 	}
@@ -230,7 +238,7 @@
 
 	ret = socfpga_vab_init(image_id);
 	if (ret < 0) {
-		ERROR("SOCFPGA VAB Authentication failed\n");
+		ERROR("SOCFPGA: VAB Authentication failed\n");
 		wfi();
 	}
 #endif
diff --git a/plat/intel/soc/agilex5/bl31_plat_setup.c b/plat/intel/soc/agilex5/bl31_plat_setup.c
index 03559e1..17d955a 100644
--- a/plat/intel/soc/agilex5/bl31_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl31_plat_setup.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2019-2024, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,7 @@
 #include "agilex5_cache.h"
 #include "agilex5_power_manager.h"
 #include "ccu/ncore_ccu.h"
+#include "socfpga_dt.h"
 #include "socfpga_mailbox.h"
 #include "socfpga_private.h"
 #include "socfpga_reset_manager.h"
@@ -146,7 +147,7 @@
 	PLAT_INTEL_SOCFPGA_G0_IRQ_PROPS(INTR_GROUP0)
 };
 
-static const gicv3_driver_data_t plat_gicv3_gic_data = {
+gicv3_driver_data_t plat_gicv3_gic_data = {
 	.gicd_base = PLAT_INTEL_SOCFPGA_GICD_BASE,
 	.gicr_base = PLAT_INTEL_SOCFPGA_GICR_BASE,
 	.interrupt_props = agx5_interrupt_props,
@@ -162,6 +163,11 @@
 {
 	socfpga_delay_timer_init();
 
+	/* TODO: DTB not available */
+	// socfpga_dt_populate_gicv3_config(SOCFPGA_DTB_BASE, &plat_gicv3_gic_data);
+	// NOTICE("SOCFPGA: GIC GICD base address 0x%lx\n", plat_gicv3_gic_data.gicd_base);
+	// NOTICE("SOCFPGA: GIC GICR base address 0x%lx\n", plat_gicv3_gic_data.gicr_base);
+
 	/* Initialize the gic cpu and distributor interfaces */
 	gicv3_driver_init(&plat_gicv3_gic_data);
 	gicv3_distif_init();
@@ -192,9 +198,9 @@
 
 	cpuid = MPIDR_AFFLVL1_VAL(read_mpidr());
 	boot_core = ((mmio_read_32(AGX5_PWRMGR(MPU_BOOTCONFIG)) & 0xC00) >> 10);
-	NOTICE("BL31: Boot Core = %x\n", boot_core);
-	NOTICE("BL31: CPU ID = %x\n", cpuid);
-	INFO("BL31: Invalidate Data cache\n");
+	NOTICE("SOCFPGA: Boot Core = %x\n", boot_core);
+	NOTICE("SOCFPGA: CPU ID = %x\n", cpuid);
+	INFO("SOCFPGA: Invalidate Data cache\n");
 	invalidate_dcache_all();
 
 	/* Invalidate for NS EL2 and EL1 */
@@ -282,6 +288,11 @@
 	mmio_write_32(AGX5_PWRMGR(MPU_PCHCTLR), pch_cpu);
 }
 
+void bl31_plat_runtime_setup(void)
+{
+	console_switch_state(CONSOLE_FLAG_RUNTIME|CONSOLE_FLAG_BOOT);
+}
+
 void bl31_plat_enable_mmu(uint32_t flags)
 {
 	/* TODO: Enable mmu when needed */
diff --git a/plat/intel/soc/agilex5/include/agilex5_system_manager.h b/plat/intel/soc/agilex5/include/agilex5_system_manager.h
index ac4bf12..8c86ab1 100644
--- a/plat/intel/soc/agilex5/include/agilex5_system_manager.h
+++ b/plat/intel/soc/agilex5/include/agilex5_system_manager.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -193,12 +193,12 @@
 #define A5D0_JTAG_ID							0xD000
 #define A5D4_JTAG_ID							0x4000D000
 #define A5F0_JTAG_ID							0xC000
-#define A5F4_JTAG_ID							0x4000F000
+#define A5F4_JTAG_ID							0x4000C000
 #define A510_JTAG_ID							0x1000
 #define A514_JTAG_ID							0x40001000
 #define A530_JTAG_ID							0x3000
 #define A534_JTAG_ID							0x40003000
-#define JTAG_ID_MASK							0xC000F000
+#define JTAG_ID_MASK							0xF000F000
 
 /* Field Masking */
 #define SYSMGR_SDMMC_DRVSEL(x)						(((x) & 0x7) << 0)
diff --git a/plat/intel/soc/agilex5/include/socfpga_plat_def.h b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
index 282958a..42d8ccf 100644
--- a/plat/intel/soc/agilex5/include/socfpga_plat_def.h
+++ b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -29,6 +29,8 @@
 #define PLAT_L2_RESET_REQ					0xB007C0DE
 #define PLAT_HANDOFF_OFFSET					0x0007F000
 #define PLAT_TIMER_BASE_ADDR					0x10D01000
+#define SOCFPGA_DTB_BASE			0x80020000
+#define DT_COMPATIBLE_STR			"arm,altera socfpga-agilex5"
 
 /* System Counter */
 /* TODO: Update back to 400MHz.
diff --git a/plat/intel/soc/agilex5/platform.mk b/plat/intel/soc/agilex5/platform.mk
index a831c39..58d4b2e 100644
--- a/plat/intel/soc/agilex5/platform.mk
+++ b/plat/intel/soc/agilex5/platform.mk
@@ -1,11 +1,12 @@
 #
 # Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
 # Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
-# Copyright (c) 2024, Altera Corporation. All rights reserved.
+# Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 include lib/xlat_tables_v2/xlat_tables.mk
+include lib/libfdt/libfdt.mk
 PLAT_INCLUDES		:=	\
 			-Iplat/intel/soc/agilex5/include/		\
 			-Iplat/intel/soc/common/drivers/		\
@@ -22,6 +23,7 @@
 
 PLAT_BL_COMMON_SOURCES	:=	\
 			${AGX5_GICv3_SOURCES}				\
+			common/fdt_wrappers.c				\
 			drivers/cadence/combo_phy/cdns_combo_phy.c	\
 			drivers/cadence/emmc/cdns_sdmmc.c	\
 			drivers/cadence/nand/cdns_nand.c	\
@@ -36,7 +38,8 @@
 			plat/intel/soc/common/drivers/ddr/ddr.c			\
 			plat/intel/soc/common/drivers/nand/nand.c			\
 			plat/intel/soc/common/lib/sha/sha.c				\
-			plat/intel/soc/common/socfpga_delay_timer.c
+			plat/intel/soc/common/socfpga_delay_timer.c	\
+			plat/intel/soc/common/socfpga_dt.c
 
 BL2_SOURCES		+=	\
 		common/desc_image_load.c				\
diff --git a/plat/intel/soc/common/fdts/agilex5_fdt.dts b/plat/intel/soc/common/fdts/agilex5_fdt.dts
new file mode 100644
index 0000000..e16034f
--- /dev/null
+++ b/plat/intel/soc/common/fdts/agilex5_fdt.dts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019-2024, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	model = "ALTERA SOCFPGA AGILEX5";
+	compatible = "arm,altera socfpga-agilex5";
+	owner = "jit.loon.lim@intel.com";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+
+		cpu_on = <0xdeadc0de>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-method = "psci";
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <0>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <1>;
+		};
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <2>;
+		};
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <3>;
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x90000000>;
+	};
+
+	gic: interrupt-controller@2c010000 {
+		compatible = "arm,gic-600", "arm,gic-v3";
+		#address-cells = <2>;
+		#interrupt-cells = <3>;
+		#size-cells = <1>;
+		#ranges;
+		interrupt-controller;
+		reg = <0x1D000000 0>, /* GICD */
+		      <0x1D060000 0>; /* GICR */
+		interrupts = <0x1 0x9 0x4>;
+	};
+
+	serial0: uart@1a200000 {
+		compatible = "arm,console-16550";
+		reg = <0x10C02000 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <0 8 0xf04>;
+		clock-frequency = <100000000>;
+		uart-baudrate = <115200>;
+	};
+
+	timer0: timer@1a040000 {
+		compatible = "arm,armv7-timer-mem";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0x1a040000 0x1000>;
+		clock-frequency = <7500000>;
+
+		frame@1a050000 {
+			frame-number = <0>;
+			interrupts = <0 2 0xf04>;
+			reg = <0x1a050000 0x1000>;
+		};
+	};
+
+};
diff --git a/plat/intel/soc/common/include/socfpga_dt.h b/plat/intel/soc/common/include/socfpga_dt.h
new file mode 100644
index 0000000..3ff4cb7
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_dt.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_DT_H
+#define SOCFPGA_DT_H
+
+
+#include <stdlib.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+/*
+ * This macro takes three arguments:
+ *   config:	Configuration identifier
+ *   name:	property namespace
+ *   callback:	populate() function
+ */
+#define SOCFPGA_REGISTER_POPULATOR(config, name, callback)			\
+	__section(".socfpga_populator") __used			\
+	static const struct socfpga_populator (name##__populator) = {		\
+		.config_type = (#config),					\
+		.info = (#name),						\
+		.populate = (callback)						\
+	}
+
+/*
+ * Populator callback
+ *
+ * This structure are used by the fconf_populate function and should only be
+ * defined by the SOCFPGA_REGISTER_POPULATOR macro.
+ */
+struct socfpga_populator {
+	/* Description of the data loaded by the callback */
+	const char *config_type;
+	const char *info;
+
+	/* Callback used by fconf_populate function with a provided config dtb.
+	 * Return 0 on success, err_code < 0 otherwise.
+	 */
+	int (*populate)(uintptr_t config);
+};
+
+/* Hardware Config related getter */
+#define hw_config__gicv3_config_getter(prop) plat_gicv3_gic_data.prop
+
+/* Function Definitions */
+int socfpga_dt_open_and_check(uintptr_t dt_addr, char *compatible_str);
+int socfpga_dt_populate_gicv3_config(uintptr_t dt_addr, gicv3_driver_data_t *plat_driver_data);
+int socfpga_dt_populate_dram_layout(uintptr_t dt_addr);
+
+#endif
diff --git a/plat/intel/soc/common/include/socfpga_system_manager.h b/plat/intel/soc/common/include/socfpga_system_manager.h
index 346cfe1..14e3804 100644
--- a/plat/intel/soc/common/include/socfpga_system_manager.h
+++ b/plat/intel/soc/common/include/socfpga_system_manager.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -36,5 +36,6 @@
 /* Function Prototype */
 uint32_t intel_hps_get_jtag_id(void);
 bool is_agilex5_A5F0(void);
+bool is_agilex5_A5F4(void);
 
 #endif /* SOCFPGA_SYSTEMMANAGER_H */
diff --git a/plat/intel/soc/common/soc/socfpga_system_manager.c b/plat/intel/soc/common/soc/socfpga_system_manager.c
index 4223b2b..789c2b6 100644
--- a/plat/intel/soc/common/soc/socfpga_system_manager.c
+++ b/plat/intel/soc/common/soc/socfpga_system_manager.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,7 +15,7 @@
 
 uint32_t intel_hps_get_jtag_id(void)
 {
-	uint32_t jtag_id = 0x00;
+	uint32_t jtag_id;
 
 	jtag_id = (mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_4)));
 
@@ -29,3 +29,9 @@
 {
 	return ((intel_hps_get_jtag_id() & JTAG_ID_MASK) == A5F0_JTAG_ID);
 }
+
+/* Check for Agilex5 SM4 B0 */
+bool is_agilex5_A5F4(void)
+{
+	return ((intel_hps_get_jtag_id() & JTAG_ID_MASK) == A5F4_JTAG_ID);
+}
diff --git a/plat/intel/soc/common/socfpga_dt.c b/plat/intel/soc/common/socfpga_dt.c
new file mode 100644
index 0000000..0333b9b
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_dt.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <platform_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "socfpga_dt.h"
+
+static const void *fdt;
+/*******************************************************************************
+ * This function checks device tree file with its header.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+int socfpga_dt_open_and_check(uintptr_t dt_addr, char *compatible_str)
+{
+	int ret = 0;
+	int node = 1;
+
+	ret = fdt_check_header((void *)dt_addr);
+
+	if (ret != 0) {
+		ERROR("SOCFPGA: FDT Header invalid\n");
+		return ret;
+	}
+
+	fdt = (const void *)dt_addr;
+
+	/* As libfdt use void *, we can't avoid this cast */
+	const void *dtb = (void *)dt_addr;
+
+	/* Assert the node offset point to compatible property */
+	node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+	if (node < 0) {
+		ERROR("SOCFPGA: Can't find `%s` compatible in dtb\n",
+						compatible_str);
+		return node;
+	}
+
+	NOTICE("SOCFPGA: Successfully open and check FDT\n");
+
+	return ret;
+}
+
+int socfpga_dt_populate_gicv3_config(uintptr_t dt_addr, gicv3_driver_data_t *plat_driver_data)
+{
+	int err;
+	int node;
+	uintptr_t addr;
+
+	/* Necessary to work with libfdt APIs */
+	const void *hw_config_dtb = (const void *)dt_addr;
+	/*
+	 * Find the offset of the node containing "arm,gic-v3" compatible property.
+	 * Populating fconf strucutures dynamically is not supported for legacy
+	 * systems which use GICv2 IP. Simply skip extracting GIC properties.
+	 */
+	node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3");
+	if (node < 0) {
+		ERROR("SOCFPGA: Unable to locate node with arm,gic-v3 compatible property\n");
+		return 0;
+	}
+	/* The GICv3 DT binding holds at least two address/size pairs,
+	 * the first describing the distributor, the second the redistributors.
+	 * See: bindings/interrupt-controller/arm,gic-v3.yaml
+	 */
+	err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL);
+	if (err < 0) {
+		ERROR("SOCFPGA: Failed to read GICD reg property of GIC node\n");
+	} else {
+		plat_driver_data->gicd_base = addr;
+	}
+
+	err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL);
+	if (err < 0) {
+		ERROR("SOCFPGA: Failed to read GICR reg property of GIC node\n");
+	} else {
+		plat_driver_data->gicr_base = addr;
+	}
+	return err;
+}
+
+int socfpga_dt_populate_dram_layout(uintptr_t dt_addr)
+{
+	int node;
+	uintptr_t addr;
+	size_t size;
+
+	/* Necessary to work with libfdt APIs */
+	const void *hw_config_dtb = (const void *)dt_addr;
+
+	/* Find 'memory' node */
+	node = fdt_node_offset_by_prop_value(hw_config_dtb, -1, "device_type",
+					     "memory", sizeof("memory"));
+	if (node < 0) {
+		NOTICE("SOCFPGA: Unable to locate 'memory' node\n");
+		return node;
+	}
+
+	int err = fdt_get_reg_props_by_index(
+			hw_config_dtb, node, 0,
+			&addr, (size_t *)&size);
+
+	NOTICE("SOCFPGA: Mem base 0x%lx, Mem size 0x%lx\n", addr, size);
+	if (err < 0) {
+		ERROR("SOCFPGA: Failed to read 'reg' property of 'memory' node\n");
+		return err;
+	}
+
+	return 0;
+}
diff --git a/plat/intel/soc/common/socfpga_sip_svc.c b/plat/intel/soc/common/socfpga_sip_svc.c
index 71a626d..d64ead7 100644
--- a/plat/intel/soc/common/socfpga_sip_svc.c
+++ b/plat/intel/soc/common/socfpga_sip_svc.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -790,7 +790,7 @@
 int intel_smmu_hps_remapper_config(uint32_t remapper_bypass)
 {
 	/* Read out the JTAG-ID from boot scratch register */
-	if (is_agilex5_A5F0() != 0) {
+	if (is_agilex5_A5F0() || is_agilex5_A5F4()) {
 		if (remapper_bypass == 0x01) {
 			g_remapper_bypass = remapper_bypass;
 			mmio_write_32(SOCFPGA_SYSMGR(SDM_BE_ARADDR_REMAP), 0);
diff --git a/plat/marvell/armada/a3k/common/a3700_common.mk b/plat/marvell/armada/a3k/common/a3700_common.mk
index e8f892d..ac47ef5 100644
--- a/plat/marvell/armada/a3k/common/a3700_common.mk
+++ b/plat/marvell/armada/a3k/common/a3700_common.mk
@@ -74,6 +74,9 @@
 BL31_SOURCES		+=	$(PLAT_FAMILY_BASE)/$(PLAT)/board/pm_src.c
 endif
 
+BUILD_UART	:= uart-images
+UART_IMAGE	:= $(BUILD_UART).tgz.bin
+
 ifdef WTP
 
 # Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
@@ -82,9 +85,6 @@
 
 TBB		:= $(WTP)/wtptp/src/TBB_Linux/release/TBB_linux
 
-BUILD_UART	:= uart-images
-UART_IMAGE	:= $(BUILD_UART).tgz.bin
-
 ifeq ($(MARVELL_SECURE_BOOT),1)
 TIM_CFG		:= $(BUILD_PLAT)/atf-tim.txt
 TIM_UART_CFG	:= $(BUILD_PLAT)/$(BUILD_UART)/atf-tim.txt
diff --git a/plat/marvell/armada/a8k/common/plat_pm.c b/plat/marvell/armada/a8k/common/plat_pm.c
index f08f08a..ae3ee37 100644
--- a/plat/marvell/armada/a8k/common/plat_pm.c
+++ b/plat/marvell/armada/a8k/common/plat_pm.c
@@ -845,7 +845,7 @@
 	.pwr_domain_on_finish = a8k_pwr_domain_on_finish,
 	.get_sys_suspend_power_state = a8k_get_sys_suspend_power_state,
 	.pwr_domain_suspend_finish = a8k_pwr_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = a8k_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = a8k_pwr_domain_pwr_down_wfi,
 	.system_off = a8k_system_off,
 	.system_reset = a8k_system_reset,
 	.validate_power_state = a8k_validate_power_state,
diff --git a/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h
index af63c0c..7b57a70 100644
--- a/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h
+++ b/plat/mediatek/drivers/apusys/mt8196/apusys_devapc_def.h
@@ -139,6 +139,6 @@
 #define APUSYS_CTRL_DAPC_RCX_SLAVE_NUM		(95)	/* 0~94 */
 
 /* Dump Config */
-#define DUMP_CFG
+#undef DUMP_CFG
 
 #endif
diff --git a/plat/mediatek/drivers/spm/mt8196/mt_spm.c b/plat/mediatek/drivers/spm/mt8196/mt_spm.c
index fee5b4c..2a82089 100644
--- a/plat/mediatek/drivers/spm/mt8196/mt_spm.c
+++ b/plat/mediatek/drivers/spm/mt8196/mt_spm.c
@@ -50,8 +50,6 @@
 #define plat_spm_lock_init()
 #endif
 
-uint32_t mt_spm_version;
-
 static uint32_t spm_irq_num;
 
 void spm_set_sysclk_settle(void)
@@ -429,12 +427,6 @@
 }
 #endif
 
-static void spm_gpio_init(void)
-{
-	gpio_set_direction(EC_SUSPEND_PIN, GPIO_DIR_OUT);
-	gpio_set_value(EC_SUSPEND_PIN, GPIO_LEVEL_HIGH);
-}
-
 int spm_boot_init(void)
 {
 	plat_spm_lock_init();
@@ -452,13 +444,9 @@
 #if defined(MT_SPM_FEATURE_SUPPORT)
 	spm_hwreq_init();
 #endif
-	spm_gpio_init();
-
 	spm_irq_num = 0xFFFFFFFF;
 
-	INFO("[%s:%d] - spm finished, version = %u, PC = 0x%x\n",
-		__func__, __LINE__,
-		mt_spm_version, mmio_read_32(MD32PCM_PC));
+	INFO("[%s], PC = 0x%x\n", __func__, mmio_read_32(MD32PCM_PC));
 	return 0;
 }
 MTK_PLAT_SETUP_1_INIT(spm_boot_init);
diff --git a/plat/mediatek/drivers/spm/mt8196/mt_spm.h b/plat/mediatek/drivers/spm/mt8196/mt_spm.h
index bc6fa44..bd5fd9c 100644
--- a/plat/mediatek/drivers/spm/mt8196/mt_spm.h
+++ b/plat/mediatek/drivers/spm/mt8196/mt_spm.h
@@ -28,9 +28,6 @@
 
 #define MT_SPM_TIME_GET(tm)	({ (tm) = el3_uptime(); })
 
-#define MT_SPM_VERSION_ES	0x0
-#define MT_SPM_VERSION_CS	0x1
-
 #define SPM_FW_NO_RESUME	1
 #define MCUSYS_MTCMOS_ON	0
 #define WAKEUP_LOG_ON		0
@@ -138,7 +135,6 @@
 void mt_spm_set_common_sodi_pcm_flags(void);
 int spm_boot_init(void);
 void spm_dvfsfw_init(uint64_t boot_up_opp, uint64_t dram_issue);
-extern uint32_t mt_spm_version;
 extern struct pwr_ctrl spm_init_ctrl;
 /* Support by bl31_plat_setup.c */
 uint32_t is_abnormal_boot(void);
diff --git a/plat/mediatek/drivers/spm/mt8196/mt_spm_conservation.c b/plat/mediatek/drivers/spm/mt8196/mt_spm_conservation.c
index 16d9f29..0365e83 100644
--- a/plat/mediatek/drivers/spm/mt8196/mt_spm_conservation.c
+++ b/plat/mediatek/drivers/spm/mt8196/mt_spm_conservation.c
@@ -58,14 +58,10 @@
 #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT)
 	__spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
 #endif
-	if (mt_spm_version == MT_SPM_VERSION_ES)
-		pwrctrl->pcm_flags |= (SPM_FLAG_ENABLE_MT8196_E1_WA |
-				       SPM_FLAG_ENABLE_MT8196_EMI_E1_WA);
 
 #ifdef MTK_SPM_IVI_SUPPORT
 	pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_MT8196_IVI;
 #endif
-
 	__spm_set_pcm_flags(pwrctrl);
 
 #ifdef HW_S1_DETECT
diff --git a/plat/mediatek/include/lib/pm/mtk_pm.h b/plat/mediatek/include/lib/pm/mtk_pm.h
index 14d005d..05293e9 100644
--- a/plat/mediatek/include/lib/pm/mtk_pm.h
+++ b/plat/mediatek/include/lib/pm/mtk_pm.h
@@ -78,7 +78,7 @@
 				    psci_power_state_t *req_state);
 	void (*get_sys_suspend_power_state)(
 				    psci_power_state_t *req_state);
-	__dead2 void (*pwr_domain_pwr_down_wfi)(
+	void (*pwr_domain_pwr_down_wfi)(
 				const psci_power_state_t *req_state);
 };
 
diff --git a/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c b/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c
index ace2700..19dcd33 100644
--- a/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c
+++ b/plat/mediatek/lib/pm/armv9_0/pwr_ctrl.c
@@ -379,7 +379,7 @@
 }
 #endif
 
-static void __dead2 pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state)
+static void pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state)
 {
 	unsigned int cpu = plat_my_core_pos();
 	int ret = MTK_CPUPM_E_NOT_SUPPORT;
@@ -390,6 +390,8 @@
 		plat_panic_handler();
 	else
 		psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 static void pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)
diff --git a/plat/mediatek/lib/pm/mtk_pm.c b/plat/mediatek/lib/pm/mtk_pm.c
index 772c2d7..553fad2 100644
--- a/plat/mediatek/lib/pm/mtk_pm.c
+++ b/plat/mediatek/lib/pm/mtk_pm.c
@@ -45,8 +45,8 @@
 		mtk_pm_ops.get_sys_suspend_power_state = ops->get_sys_suspend_power_state;
 	}
 
-	if (!mtk_pm_ops.pwr_domain_pwr_down_wfi)
-		mtk_pm_ops.pwr_domain_pwr_down_wfi = ops->pwr_domain_pwr_down_wfi;
+	if (!mtk_pm_ops.pwr_domain_pwr_down)
+		mtk_pm_ops.pwr_domain_pwr_down = ops->pwr_domain_pwr_down_wfi;
 
 	mtk_pm_status |= MTK_PM_ST_PWR_READY;
 #endif
diff --git a/plat/mediatek/mt8196/drivers/gpio/mtgpio.c b/plat/mediatek/mt8196/drivers/gpio/mtgpio.c
index 6257159..a34f706 100644
--- a/plat/mediatek/mt8196/drivers/gpio/mtgpio.c
+++ b/plat/mediatek/mt8196/drivers/gpio/mtgpio.c
@@ -23,7 +23,8 @@
 	REG_11,
 	REG_12,
 	REG_13,
-	REG_14
+	REG_14,
+	REG_15
 } RegEnum;
 
 uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
@@ -37,48 +38,51 @@
 
 	switch (gpio_info.base & 0xF) {
 	case REG_0:
-		reg_addr = IOCFG_RT_BASE;
+		reg_addr = GPIO_BASE;
 		break;
 	case REG_1:
-		reg_addr = IOCFG_RM1_BASE;
+		reg_addr = IOCFG_RT_BASE;
 		break;
 	case REG_2:
-		reg_addr = IOCFG_RM2_BASE;
+		reg_addr = IOCFG_RM1_BASE;
 		break;
 	case REG_3:
-		reg_addr = IOCFG_RB_BASE;
+		reg_addr = IOCFG_RM2_BASE;
 		break;
 	case REG_4:
-		reg_addr = IOCFG_BM1_BASE;
+		reg_addr = IOCFG_RB_BASE;
 		break;
 	case REG_5:
-		reg_addr = IOCFG_BM2_BASE;
+		reg_addr = IOCFG_BM1_BASE;
 		break;
 	case REG_6:
-		reg_addr = IOCFG_BM3_BASE;
+		reg_addr = IOCFG_BM2_BASE;
 		break;
 	case REG_7:
-		reg_addr = IOCFG_LT_BASE;
+		reg_addr = IOCFG_BM3_BASE;
 		break;
 	case REG_8:
-		reg_addr = IOCFG_LM1_BASE;
+		reg_addr = IOCFG_LT_BASE;
 		break;
 	case REG_9:
-		reg_addr = IOCFG_LM2_BASE;
+		reg_addr = IOCFG_LM1_BASE;
 		break;
 	case REG_10:
-		reg_addr = IOCFG_LB1_BASE;
+		reg_addr = IOCFG_LM2_BASE;
 		break;
 	case REG_11:
-		reg_addr = IOCFG_LB2_BASE;
+		reg_addr = IOCFG_LB1_BASE;
 		break;
 	case REG_12:
-		reg_addr = IOCFG_TM1_BASE;
+		reg_addr = IOCFG_LB2_BASE;
 		break;
 	case REG_13:
-		reg_addr = IOCFG_TM2_BASE;
+		reg_addr = IOCFG_TM1_BASE;
 		break;
 	case REG_14:
+		reg_addr = IOCFG_TM2_BASE;
+		break;
+	case REG_15:
 		reg_addr = IOCFG_TM3_BASE;
 		break;
 	default:
diff --git a/plat/mediatek/mt8196/drivers/gpio/mtgpio.h b/plat/mediatek/mt8196/drivers/gpio/mtgpio.h
index a33bdad..ef8ee8c 100644
--- a/plat/mediatek/mt8196/drivers/gpio/mtgpio.h
+++ b/plat/mediatek/mt8196/drivers/gpio/mtgpio.h
@@ -50,131 +50,131 @@
 } GPIO_PIN;
 
 static const struct mt_pin_info mt_pin_infos[] = {
-	PIN(0, 0, 0, 0x18, 0x90),
-	PIN(1, 0, 1, 0x18, 0x90),
-	PIN(2, 0, 1, 0x1b, 0x70),
-	PIN(3, 0, 2, 0x1b, 0x70),
-	PIN(4, 0, 3, 0x1b, 0x70),
-	PIN(5, 0, 4, 0x1b, 0x70),
-	PIN(6, 0, 5, 0x1b, 0x70),
-	PIN(7, 0, 6, 0x1b, 0x70),
-	PIN(8, 0, 7, 0x1b, 0x70),
-	PIN(9, 0, 14, 0x29, 0xa0),
-	PIN(10, 0, 12, 0x29, 0xa0),
-	PIN(11, 0, 2, 0x18, 0x90),
-	PIN(12, 0, 13, 0x29, 0xa0),
-	PIN(13, 0, 1, 0x26, 0x90),
-	PIN(14, 0, 0, 0x13, 0x80),
-	PIN(15, 0, 2, 0x26, 0x90),
-	PIN(16, 0, 3, 0x26, 0x90),
-	PIN(17, 0, 4, 0x26, 0x90),
-	PIN(18, 0, 5, 0x26, 0x90),
-	PIN(19, 0, 6, 0x26, 0x90),
-	PIN(20, 0, 1, 0x13, 0x80),
-	PIN(21, 0, 3, 0x12, 0x80),
-	PIN(22, 0, 4, 0x12, 0x80),
-	PIN(23, 0, 5, 0x12, 0x80),
-	PIN(24, 0, 6, 0x12, 0x80),
-	PIN(25, 0, 7, 0x12, 0x80),
-	PIN(26, 0, 8, 0x12, 0x80),
-	PIN(27, 0, 9, 0x12, 0x80),
-	PIN(28, 0, 10, 0x12, 0x80),
-	PIN(29, 0, 11, 0x12, 0x80),
-	PIN(30, 0, 12, 0x12, 0x80),
-	PIN(31, 0, 13, 0x12, 0x80),
-	PIN(32, 0, 8, 0x11, 0x80),
-	PIN(33, 0, 9, 0x11, 0x80),
-	PIN(34, 0, 10, 0x11, 0x80),
-	PIN(35, 0, 11, 0x11, 0x80),
-	PIN(36, 0, 12, 0x11, 0x80),
-	PIN(37, 0, 13, 0x11, 0x80),
-	PIN(38, 0, 14, 0x11, 0x80),
-	PIN(39, 0, 6, 0x18, 0x90),
-	PIN(40, 0, 3, 0x18, 0x90),
-	PIN(41, 0, 5, 0x18, 0x90),
-	PIN(42, 0, 4, 0x18, 0x90),
-	PIN(43, 0, 7, 0x18, 0x90),
-	PIN(44, 0, 8, 0x18, 0x90),
-	PIN(45, 0, 9, 0x18, 0x90),
-	PIN(46, 0, 10, 0x18, 0x90),
-	PIN(47, 0, 13, 0x18, 0x90),
-	PIN(48, 0, 11, 0x18, 0x90),
-	PIN(49, 0, 14, 0x18, 0x90),
-	PIN(50, 0, 12, 0x18, 0x90),
-	PIN(51, 0, 15, 0x18, 0x90),
-	PIN(52, 0, 7, 0x29, 0xa0),
-	PIN(53, 0, 8, 0x29, 0xa0),
-	PIN(54, 0, 2, 0x29, 0xa0),
-	PIN(55, 0, 1, 0x29, 0xa0),
-	PIN(56, 0, 5, 0x29, 0xa0),
-	PIN(57, 0, 6, 0x29, 0xa0),
-	PIN(58, 0, 3, 0x29, 0xa0),
-	PIN(59, 0, 4, 0x29, 0xa0),
+	PIN(0, 0, 0, 0x18, 0xa0),
+	PIN(1, 0, 1, 0x18, 0xa0),
+	PIN(2, 0, 1, 0x1b, 0x80),
+	PIN(3, 0, 2, 0x1b, 0x80),
+	PIN(4, 0, 3, 0x1b, 0x80),
+	PIN(5, 0, 4, 0x1b, 0x80),
+	PIN(6, 0, 5, 0x1b, 0x80),
+	PIN(7, 0, 6, 0x1b, 0x80),
+	PIN(8, 0, 7, 0x1b, 0x80),
+	PIN(9, 0, 14, 0x29, 0xc0),
+	PIN(10, 0, 12, 0x29, 0xc0),
+	PIN(11, 0, 2, 0x18, 0xa0),
+	PIN(12, 0, 13, 0x29, 0xc0),
+	PIN(13, 0, 1, 0x26, 0xb0),
+	PIN(14, 0, 0, 0x13, 0x90),
+	PIN(15, 0, 2, 0x26, 0xb0),
+	PIN(16, 0, 3, 0x26, 0xb0),
+	PIN(17, 0, 4, 0x26, 0xb0),
+	PIN(18, 0, 5, 0x26, 0xb0),
+	PIN(19, 0, 6, 0x26, 0xb0),
+	PIN(20, 0, 1, 0x13, 0x90),
+	PIN(21, 0, 3, 0x12, 0x90),
+	PIN(22, 0, 4, 0x12, 0x90),
+	PIN(23, 0, 5, 0x12, 0x90),
+	PIN(24, 0, 6, 0x12, 0x90),
+	PIN(25, 0, 7, 0x12, 0x90),
+	PIN(26, 0, 8, 0x12, 0x90),
+	PIN(27, 0, 9, 0x12, 0x90),
+	PIN(28, 0, 10, 0x12, 0x90),
+	PIN(29, 0, 11, 0x12, 0x90),
+	PIN(30, 0, 12, 0x12, 0x90),
+	PIN(31, 0, 13, 0x12, 0x90),
+	PIN(32, 0, 8, 0x11, 0x90),
+	PIN(33, 0, 9, 0x11, 0x90),
+	PIN(34, 0, 10, 0x11, 0x90),
+	PIN(35, 0, 11, 0x11, 0x90),
+	PIN(36, 0, 12, 0x11, 0x90),
+	PIN(37, 0, 13, 0x11, 0x90),
+	PIN(38, 0, 14, 0x11, 0x90),
+	PIN(39, 0, 6, 0x18, 0xa0),
+	PIN(40, 0, 3, 0x18, 0xa0),
+	PIN(41, 0, 5, 0x18, 0xa0),
+	PIN(42, 0, 4, 0x18, 0xa0),
+	PIN(43, 0, 7, 0x18, 0xa0),
+	PIN(44, 0, 8, 0x18, 0xa0),
+	PIN(45, 0, 9, 0x18, 0xa0),
+	PIN(46, 0, 10, 0x18, 0xa0),
+	PIN(47, 0, 13, 0x18, 0xa0),
+	PIN(48, 0, 11, 0x18, 0xa0),
+	PIN(49, 0, 14, 0x18, 0xa0),
+	PIN(50, 0, 12, 0x18, 0xa0),
+	PIN(51, 0, 15, 0x18, 0xa0),
+	PIN(52, 0, 7, 0x29, 0xc0),
+	PIN(53, 0, 8, 0x29, 0xc0),
+	PIN(54, 0, 2, 0x29, 0xc0),
+	PIN(55, 0, 1, 0x29, 0xc0),
+	PIN(56, 0, 5, 0x29, 0xc0),
+	PIN(57, 0, 6, 0x29, 0xc0),
+	PIN(58, 0, 3, 0x29, 0xc0),
+	PIN(59, 0, 4, 0x29, 0xc0),
 	PIN(60, 1, 0, 0x29, 0xb0),
-	PIN(61, 0, 10, 0x29, 0xa0),
-	PIN(62, 0, 9, 0x29, 0xa0),
-	PIN(63, 0, 18, 0x29, 0xa0),
-	PIN(64, 0, 0, 0x29, 0xa0),
-	PIN(65, 0, 11, 0x29, 0xa0),
-	PIN(66, 0, 24, 0x29, 0xa0),
-	PIN(67, 0, 21, 0x29, 0xa0),
-	PIN(68, 0, 20, 0x29, 0xa0),
-	PIN(69, 0, 25, 0x29, 0xa0),
-	PIN(70, 0, 16, 0x29, 0xa0),
-	PIN(71, 0, 15, 0x29, 0xa0),
-	PIN(72, 0, 23, 0x29, 0xa0),
-	PIN(73, 0, 19, 0x29, 0xa0),
-	PIN(74, 0, 17, 0x29, 0xa0),
-	PIN(75, 0, 2, 0x1a, 0x80),
-	PIN(76, 0, 3, 0x1a, 0x80),
-	PIN(77, 0, 4, 0x1a, 0x80),
-	PIN(78, 0, 5, 0x1a, 0x80),
-	PIN(79, 0, 0, 0x1a, 0x80),
-	PIN(80, 0, 1, 0x1a, 0x80),
-	PIN(81, 0, 9, 0x1b, 0x70),
-	PIN(82, 0, 10, 0x1b, 0x70),
-	PIN(83, 0, 12, 0x1b, 0x70),
-	PIN(84, 0, 11, 0x1b, 0x70),
-	PIN(85, 0, 13, 0x1b, 0x70),
-	PIN(86, 0, 14, 0x1b, 0x70),
-	PIN(87, 0, 16, 0x1b, 0x70),
-	PIN(88, 0, 15, 0x1b, 0x70),
-	PIN(89, 0, 0, 0x1b, 0x70),
-	PIN(90, 0, 8, 0x1b, 0x70),
-	PIN(91, 0, 6, 0x1c, 0x80),
-	PIN(92, 0, 7, 0x1c, 0x80),
-	PIN(93, 0, 8, 0x1c, 0x80),
-	PIN(94, 0, 4, 0x1c, 0x80),
-	PIN(95, 0, 1, 0x1c, 0x80),
-	PIN(96, 0, 3, 0x1c, 0x80),
-	PIN(97, 0, 2, 0x1c, 0x80),
-	PIN(98, 0, 5, 0x1c, 0x80),
-	PIN(99, 0, 9, 0x1c, 0x80),
-	PIN(100, 0, 12, 0x1c, 0x80),
-	PIN(101, 0, 10, 0x1c, 0x80),
-	PIN(102, 0, 13, 0x1c, 0x80),
-	PIN(103, 0, 0, 0x1c, 0x80),
-	PIN(104, 0, 11, 0x1c, 0x80),
-	PIN(105, 0, 14, 0x1c, 0x80),
-	PIN(106, 0, 0, 0x15, 0x80),
-	PIN(107, 0, 1, 0x15, 0x80),
-	PIN(108, 0, 3, 0x15, 0x80),
-	PIN(109, 0, 2, 0x15, 0x80),
-	PIN(110, 0, 4, 0x15, 0x80),
-	PIN(111, 0, 5, 0x15, 0x80),
-	PIN(112, 0, 7, 0x15, 0x80),
-	PIN(113, 0, 6, 0x15, 0x80),
-	PIN(114, 0, 8, 0x15, 0x80),
-	PIN(115, 0, 9, 0x15, 0x80),
-	PIN(116, 0, 11, 0x15, 0x80),
-	PIN(117, 0, 10, 0x15, 0x80),
-	PIN(118, 0, 9, 0x26, 0x90),
-	PIN(119, 0, 10, 0x26, 0x90),
-	PIN(120, 0, 12, 0x26, 0x90),
-	PIN(121, 0, 11, 0x26, 0x90),
-	PIN(122, 0, 0, 0x26, 0x90),
-	PIN(123, 0, 7, 0x26, 0x90),
-	PIN(124, 0, 8, 0x26, 0x90),
+	PIN(61, 0, 10, 0x29, 0xc0),
+	PIN(62, 0, 9, 0x29, 0xc0),
+	PIN(63, 0, 18, 0x29, 0xc0),
+	PIN(64, 0, 0, 0x29, 0xc0),
+	PIN(65, 0, 11, 0x29, 0xc0),
+	PIN(66, 0, 24, 0x29, 0xc0),
+	PIN(67, 0, 21, 0x29, 0xc0),
+	PIN(68, 0, 20, 0x29, 0xc0),
+	PIN(69, 0, 25, 0x29, 0xc0),
+	PIN(70, 0, 16, 0x29, 0xc0),
+	PIN(71, 0, 15, 0x29, 0xc0),
+	PIN(72, 0, 23, 0x29, 0xc0),
+	PIN(73, 0, 19, 0x29, 0xc0),
+	PIN(74, 0, 17, 0x29, 0xc0),
+	PIN(75, 0, 2, 0x1a, 0x90),
+	PIN(76, 0, 3, 0x1a, 0x90),
+	PIN(77, 0, 4, 0x1a, 0x90),
+	PIN(78, 0, 5, 0x1a, 0x90),
+	PIN(79, 0, 0, 0x1a, 0x90),
+	PIN(80, 0, 1, 0x1a, 0x90),
+	PIN(81, 0, 9, 0x1b, 0x80),
+	PIN(82, 0, 10, 0x1b, 0x80),
+	PIN(83, 0, 12, 0x1b, 0x80),
+	PIN(84, 0, 11, 0x1b, 0x80),
+	PIN(85, 0, 13, 0x1b, 0x80),
+	PIN(86, 0, 14, 0x1b, 0x80),
+	PIN(87, 0, 16, 0x1b, 0x80),
+	PIN(88, 0, 15, 0x1b, 0x80),
+	PIN(89, 0, 0, 0x1b, 0x80),
+	PIN(90, 0, 8, 0x1b, 0x80),
+	PIN(91, 0, 6, 0x1c, 0x90),
+	PIN(92, 0, 7, 0x1c, 0x90),
+	PIN(93, 0, 8, 0x1c, 0x90),
+	PIN(94, 0, 4, 0x1c, 0x90),
+	PIN(95, 0, 1, 0x1c, 0x90),
+	PIN(96, 0, 3, 0x1c, 0x90),
+	PIN(97, 0, 2, 0x1c, 0x90),
+	PIN(98, 0, 5, 0x1c, 0x90),
+	PIN(99, 0, 9, 0x1c, 0x90),
+	PIN(100, 0, 12, 0x1c, 0x90),
+	PIN(101, 0, 10, 0x1c, 0x90),
+	PIN(102, 0, 13, 0x1c, 0x90),
+	PIN(103, 0, 0, 0x1c, 0x90),
+	PIN(104, 0, 11, 0x1c, 0x90),
+	PIN(105, 0, 14, 0x1c, 0x90),
+	PIN(106, 0, 0, 0x15, 0x90),
+	PIN(107, 0, 1, 0x15, 0x90),
+	PIN(108, 0, 3, 0x15, 0x90),
+	PIN(109, 0, 2, 0x15, 0x90),
+	PIN(110, 0, 4, 0x15, 0x90),
+	PIN(111, 0, 5, 0x15, 0x90),
+	PIN(112, 0, 7, 0x15, 0x90),
+	PIN(113, 0, 6, 0x15, 0x90),
+	PIN(114, 0, 8, 0x15, 0x90),
+	PIN(115, 0, 9, 0x15, 0x90),
+	PIN(116, 0, 11, 0x15, 0x90),
+	PIN(117, 0, 10, 0x15, 0x90),
+	PIN(118, 0, 9, 0x26, 0xb0),
+	PIN(119, 0, 10, 0x26, 0xb0),
+	PIN(120, 0, 12, 0x26, 0xb0),
+	PIN(121, 0, 11, 0x26, 0xb0),
+	PIN(122, 0, 0, 0x26, 0xb0),
+	PIN(123, 0, 7, 0x26, 0xb0),
+	PIN(124, 0, 8, 0x26, 0xb0),
 	PIN(125, 1, 0, 0x17, 0x80),
 	PIN(126, 1, 1, 0x17, 0x80),
 	PIN(127, 1, 2, 0x17, 0x80),
@@ -207,108 +207,108 @@
 	PIN(154, 1, 8, 0x14, 0x70),
 	PIN(155, 1, 18, 0x14, 0x70),
 	PIN(156, 1, 19, 0x14, 0x70),
-	PIN(157, 0, 1, 0x12, 0x80),
-	PIN(158, 0, 2, 0x12, 0x80),
-	PIN(159, 0, 0, 0x12, 0x80),
-	PIN(160, 0, 22, 0x13, 0x80),
-	PIN(161, 0, 20, 0x13, 0x80),
-	PIN(162, 0, 23, 0x13, 0x80),
-	PIN(163, 0, 21, 0x13, 0x80),
-	PIN(164, 0, 12, 0x13, 0x80),
-	PIN(165, 0, 14, 0x13, 0x80),
-	PIN(166, 0, 13, 0x13, 0x80),
-	PIN(167, 0, 15, 0x13, 0x80),
-	PIN(168, 0, 16, 0x13, 0x80),
-	PIN(169, 0, 17, 0x13, 0x80),
-	PIN(170, 0, 19, 0x13, 0x80),
-	PIN(171, 0, 18, 0x13, 0x80),
-	PIN(172, 0, 10, 0x13, 0x80),
-	PIN(173, 0, 11, 0x13, 0x80),
-	PIN(174, 0, 15, 0x11, 0x80),
-	PIN(175, 0, 16, 0x11, 0x80),
-	PIN(176, 0, 17, 0x11, 0x80),
-	PIN(177, 0, 18, 0x11, 0x80),
-	PIN(178, 0, 6, 0x11, 0x80),
-	PIN(179, 0, 7, 0x11, 0x80),
-	PIN(180, 0, 0, 0x11, 0x80),
-	PIN(181, 0, 1, 0x11, 0x80),
-	PIN(182, 0, 2, 0x11, 0x80),
-	PIN(183, 0, 3, 0x11, 0x80),
-	PIN(184, 0, 4, 0x11, 0x80),
-	PIN(185, 0, 5, 0x11, 0x80),
-	PIN(186, 0, 4, 0x1d, 0xc0),
-	PIN(187, 0, 5, 0x1d, 0xc0),
-	PIN(188, 0, 12, 0x1d, 0xc0),
-	PIN(189, 0, 17, 0x1d, 0xc0),
-	PIN(190, 0, 13, 0x1d, 0xc0),
-	PIN(191, 0, 18, 0x1d, 0xc0),
-	PIN(192, 0, 0, 0x1d, 0xc0),
-	PIN(193, 0, 6, 0x1d, 0xc0),
-	PIN(194, 0, 14, 0x1d, 0xc0),
-	PIN(195, 0, 19, 0x1d, 0xc0),
-	PIN(196, 0, 1, 0x1d, 0xc0),
-	PIN(197, 0, 7, 0x1d, 0xc0),
-	PIN(198, 0, 15, 0x1d, 0xc0),
-	PIN(199, 0, 20, 0x1d, 0xc0),
-	PIN(200, 0, 22, 0x1d, 0xc0),
-	PIN(201, 0, 25, 0x1d, 0xc0),
-	PIN(202, 0, 16, 0x1d, 0xc0),
-	PIN(203, 0, 21, 0x1d, 0xc0),
-	PIN(204, 0, 2, 0x1d, 0xc0),
-	PIN(205, 0, 3, 0x1d, 0xc0),
-	PIN(206, 0, 8, 0x1d, 0xc0),
-	PIN(207, 0, 9, 0x1d, 0xc0),
-	PIN(208, 0, 10, 0x1d, 0xc0),
-	PIN(209, 0, 11, 0x1d, 0xc0),
-	PIN(210, 0, 0, 0x2e, 0x90),
-	PIN(211, 0, 1, 0x2e, 0x90),
-	PIN(212, 0, 2, 0x2e, 0x90),
-	PIN(213, 0, 3, 0x2e, 0x90),
-	PIN(214, 0, 23, 0x1d, 0xc0),
-	PIN(215, 0, 24, 0x1d, 0xc0),
-	PIN(216, 0, 4, 0x2e, 0x90),
+	PIN(157, 0, 1, 0x12, 0x90),
+	PIN(158, 0, 2, 0x12, 0x90),
+	PIN(159, 0, 0, 0x12, 0x90),
+	PIN(160, 0, 22, 0x13, 0x90),
+	PIN(161, 0, 20, 0x13, 0x90),
+	PIN(162, 0, 23, 0x13, 0x90),
+	PIN(163, 0, 21, 0x13, 0x90),
+	PIN(164, 0, 12, 0x13, 0x90),
+	PIN(165, 0, 14, 0x13, 0x90),
+	PIN(166, 0, 13, 0x13, 0x90),
+	PIN(167, 0, 15, 0x13, 0x90),
+	PIN(168, 0, 16, 0x13, 0x90),
+	PIN(169, 0, 17, 0x13, 0x90),
+	PIN(170, 0, 19, 0x13, 0x90),
+	PIN(171, 0, 18, 0x13, 0x90),
+	PIN(172, 0, 10, 0x13, 0x90),
+	PIN(173, 0, 11, 0x13, 0x90),
+	PIN(174, 0, 15, 0x11, 0x90),
+	PIN(175, 0, 16, 0x11, 0x90),
+	PIN(176, 0, 17, 0x11, 0x90),
+	PIN(177, 0, 18, 0x11, 0x90),
+	PIN(178, 0, 6, 0x11, 0x90),
+	PIN(179, 0, 7, 0x11, 0x90),
+	PIN(180, 0, 0, 0x11, 0x90),
+	PIN(181, 0, 1, 0x11, 0x90),
+	PIN(182, 0, 2, 0x11, 0x90),
+	PIN(183, 0, 3, 0x11, 0x90),
+	PIN(184, 0, 4, 0x11, 0x90),
+	PIN(185, 0, 5, 0x11, 0x90),
+	PIN(186, 0, 4, 0x1d, 0xd0),
+	PIN(187, 0, 5, 0x1d, 0xd0),
+	PIN(188, 0, 12, 0x1d, 0xd0),
+	PIN(189, 0, 17, 0x1d, 0xd0),
+	PIN(190, 0, 13, 0x1d, 0xd0),
+	PIN(191, 0, 18, 0x1d, 0xd0),
+	PIN(192, 0, 0, 0x1d, 0xd0),
+	PIN(193, 0, 6, 0x1d, 0xd0),
+	PIN(194, 0, 14, 0x1d, 0xd0),
+	PIN(195, 0, 19, 0x1d, 0xd0),
+	PIN(196, 0, 1, 0x1d, 0xd0),
+	PIN(197, 0, 7, 0x1d, 0xd0),
+	PIN(198, 0, 15, 0x1d, 0xd0),
+	PIN(199, 0, 20, 0x1d, 0xd0),
+	PIN(200, 0, 22, 0x1d, 0xd0),
+	PIN(201, 0, 25, 0x1d, 0xd0),
+	PIN(202, 0, 16, 0x1d, 0xd0),
+	PIN(203, 0, 21, 0x1d, 0xd0),
+	PIN(204, 0, 2, 0x1d, 0xd0),
+	PIN(205, 0, 3, 0x1d, 0xd0),
+	PIN(206, 0, 8, 0x1d, 0xd0),
+	PIN(207, 0, 9, 0x1d, 0xd0),
+	PIN(208, 0, 10, 0x1d, 0xd0),
+	PIN(209, 0, 11, 0x1d, 0xd0),
+	PIN(210, 0, 0, 0x2e, 0xb0),
+	PIN(211, 0, 1, 0x2e, 0xb0),
+	PIN(212, 0, 2, 0x2e, 0xb0),
+	PIN(213, 0, 3, 0x2e, 0xb0),
+	PIN(214, 0, 23, 0x1d, 0xd0),
+	PIN(215, 0, 24, 0x1d, 0xd0),
+	PIN(216, 0, 4, 0x2e, 0xb0),
 	PIN(217, 1, 1, 0x2e, 0xa0),
 	PIN(218, 1, 2, 0x2e, 0xa0),
 	PIN(219, 1, 0, 0x2e, 0xa0),
-	PIN(220, 0, 5, 0x2e, 0x90),
-	PIN(221, 0, 6, 0x2e, 0x90),
-	PIN(222, 0, 8, 0x2e, 0x90),
-	PIN(223, 0, 7, 0x2e, 0x90),
+	PIN(220, 0, 5, 0x2e, 0xb0),
+	PIN(221, 0, 6, 0x2e, 0xb0),
+	PIN(222, 0, 8, 0x2e, 0xb0),
+	PIN(223, 0, 7, 0x2e, 0xb0),
 	PIN(224, 1, 3, 0x2e, 0xa0),
 	PIN(225, 1, 4, 0x2e, 0xa0),
 	PIN(226, 1, 5, 0x2e, 0xa0),
 	PIN(227, 1, 6, 0x2e, 0xa0),
 	PIN(228, 1, 7, 0x2e, 0xa0),
 	PIN(229, 1, 8, 0x2e, 0xa0),
-	PIN(230, 0, 13, 0x2f, 0x70),
-	PIN(231, 0, 14, 0x2f, 0x70),
-	PIN(232, 0, 10, 0x2f, 0x70),
-	PIN(233, 0, 0, 0x2f, 0x70),
-	PIN(234, 0, 3, 0x2f, 0x70),
-	PIN(235, 0, 1, 0x2f, 0x70),
-	PIN(236, 0, 2, 0x2f, 0x70),
-	PIN(237, 0, 6, 0x2f, 0x70),
-	PIN(238, 0, 5, 0x2f, 0x70),
-	PIN(239, 0, 19, 0x2f, 0x70),
-	PIN(240, 0, 18, 0x2f, 0x70),
-	PIN(241, 0, 16, 0x2f, 0x70),
-	PIN(242, 0, 17, 0x2f, 0x70),
-	PIN(243, 0, 15, 0x2f, 0x70),
-	PIN(244, 0, 12, 0x2f, 0x70),
-	PIN(245, 0, 9, 0x2f, 0x70),
-	PIN(246, 0, 8, 0x2f, 0x70),
-	PIN(247, 0, 7, 0x2f, 0x70),
-	PIN(248, 0, 4, 0x2f, 0x70),
-	PIN(249, 0, 20, 0x2f, 0x70),
-	PIN(250, 0, 11, 0x2f, 0x70),
-	PIN(251, 0, 2, 0x13, 0x80),
-	PIN(252, 0, 3, 0x13, 0x80),
-	PIN(253, 0, 4, 0x13, 0x80),
-	PIN(254, 0, 5, 0x13, 0x80),
-	PIN(255, 0, 6, 0x13, 0x80),
-	PIN(256, 0, 7, 0x13, 0x80),
-	PIN(257, 0, 8, 0x13, 0x80),
-	PIN(258, 0, 9, 0x13, 0x80),
+	PIN(230, 0, 13, 0x2f, 0x90),
+	PIN(231, 0, 14, 0x2f, 0x90),
+	PIN(232, 0, 10, 0x2f, 0x90),
+	PIN(233, 0, 0, 0x2f, 0x90),
+	PIN(234, 0, 3, 0x2f, 0x90),
+	PIN(235, 0, 1, 0x2f, 0x90),
+	PIN(236, 0, 2, 0x2f, 0x90),
+	PIN(237, 0, 6, 0x2f, 0x90),
+	PIN(238, 0, 5, 0x2f, 0x90),
+	PIN(239, 0, 19, 0x2f, 0x90),
+	PIN(240, 0, 18, 0x2f, 0x90),
+	PIN(241, 0, 16, 0x2f, 0x90),
+	PIN(242, 0, 17, 0x2f, 0x90),
+	PIN(243, 0, 15, 0x2f, 0x90),
+	PIN(244, 0, 12, 0x2f, 0x90),
+	PIN(245, 0, 9, 0x2f, 0x90),
+	PIN(246, 0, 8, 0x2f, 0x90),
+	PIN(247, 0, 7, 0x2f, 0x90),
+	PIN(248, 0, 4, 0x2f, 0x90),
+	PIN(249, 0, 20, 0x2f, 0x90),
+	PIN(250, 0, 11, 0x2f, 0x90),
+	PIN(251, 0, 2, 0x13, 0x90),
+	PIN(252, 0, 3, 0x13, 0x90),
+	PIN(253, 0, 4, 0x13, 0x90),
+	PIN(254, 0, 5, 0x13, 0x90),
+	PIN(255, 0, 6, 0x13, 0x90),
+	PIN(256, 0, 7, 0x13, 0x90),
+	PIN(257, 0, 8, 0x13, 0x90),
+	PIN(258, 0, 9, 0x13, 0x90),
 	PIN(259, 1, 9, 0x2e, 0xa0),
 	PIN(260, 1, 10, 0x2e, 0xa0),
 	PIN(261, 1, 11, 0x2e, 0xa0),
diff --git a/plat/nuvoton/npcm845x/npcm845x_psci.c b/plat/nuvoton/npcm845x/npcm845x_psci.c
index a954265..6e9523e 100644
--- a/plat/nuvoton/npcm845x/npcm845x_psci.c
+++ b/plat/nuvoton/npcm845x/npcm845x_psci.c
@@ -384,7 +384,7 @@
 
 	/* For testing purposes only This PSCI states are not supported */
 	.pwr_domain_off = npcm845x_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi = npcm845x_pwr_down_wfi,
+	.pwr_domain_pwr_down = npcm845x_pwr_down_wfi,
 };
 
 /* For reference only
@@ -400,7 +400,7 @@
  *				const psci_power_state_t *target_state);
  *	void (*pwr_domain_suspend_finish)(
  *				const psci_power_state_t *target_state);
- *	void __dead2 (*pwr_domain_pwr_down_wfi)(
+ *	void __dead2 (*pwr_domain_pwr_down    )(
  *				const psci_power_state_t *target_state);
  *	void __dead2 (*system_off)(void);
  *	void __dead2 (*system_reset)(void);
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c
index 8edb024..234cb6b 100644
--- a/plat/nvidia/tegra/common/tegra_pm.c
+++ b/plat/nvidia/tegra/common/tegra_pm.c
@@ -284,7 +284,7 @@
 	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
 	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi	= tegra_pwr_domain_power_down_wfi,
+	.pwr_domain_pwr_down		= tegra_pwr_domain_power_down_wfi,
 	.system_off			= tegra_system_off,
 	.system_reset			= tegra_system_reset,
 	.validate_power_state		= tegra_validate_power_state,
diff --git a/plat/nxp/common/psci/plat_psci.c b/plat/nxp/common/psci/plat_psci.c
index f6dd7b3..c154a7f 100644
--- a/plat/nxp/common/psci/plat_psci.c
+++ b/plat/nxp/common/psci/plat_psci.c
@@ -433,7 +433,7 @@
 	.pwr_domain_off	= _pwr_domain_off,
 #endif
 #if (SOC_CORE_OFF || SOC_CORE_PWR_DWN)
-	.pwr_domain_pwr_down_wfi = _pwr_down_wfi,
+	.pwr_domain_pwr_down = _pwr_down_wfi,
 #endif
 #if (SOC_CORE_STANDBY || SOC_CORE_PWR_DWN)
 	 /* cpu_suspend */
diff --git a/plat/qemu/common/common.mk b/plat/qemu/common/common.mk
index 5e3a61a..da981e5 100644
--- a/plat/qemu/common/common.mk
+++ b/plat/qemu/common/common.mk
@@ -23,7 +23,6 @@
 				lib/cpus/aarch64/cortex_a72.S		\
 				lib/cpus/aarch64/cortex_a76.S		\
 				lib/cpus/aarch64/cortex_a710.S		\
-				lib/cpus/aarch64/neoverse_n_common.S	\
 				lib/cpus/aarch64/neoverse_n1.S		\
 				lib/cpus/aarch64/neoverse_v1.S		\
 				lib/cpus/aarch64/neoverse_n2.S		\
@@ -153,4 +152,12 @@
 PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c
 endif
 
+ifeq (${TRANSFER_LIST}, 1)
+include lib/transfer_list/transfer_list.mk
+endif
+
+ifeq (${HOB_LIST}, 1)
+include lib/hob/hob.mk
+endif
+
 endif
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index 81ce102..1c5e0ea 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -46,6 +46,30 @@
 					MT_DEVICE | MT_RW | EL3_PAS)
 #endif
 
+#if ENABLE_RME
+#if (RME_GPT_BITLOCK_BLOCK == 0)
+#define BITLOCK_BASE	UL(0)
+#define BITLOCK_SIZE	UL(0)
+#else
+
+/*
+ * Number of bitlock_t entries in the gpt_bitlock array for this platform's
+ * Protected Physical Size. One 8-bit bitlock_t entry covers
+ * 8 * RME_GPT_BITLOCK_BLOCK * 512MB.
+ */
+#if (PLAT_QEMU_PPS > (RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8)))
+#define BITLOCKS_NUM	(PLAT_QEMU_PPS /	\
+			(RME_GPT_BITLOCK_BLOCK * SZ_512M * UL(8)))
+#else
+#define BITLOCKS_NUM	1
+#endif
+
+static bitlock_t gpt_bitlock[BITLOCKS_NUM];
+#define BITLOCK_BASE	(uintptr_t)gpt_bitlock
+#define BITLOCK_SIZE	sizeof(gpt_bitlock)
+#endif /* RME_GPT_BITLOCK_BLOCK */
+#endif /* ENABLE_RME */
+
 /*
  * Placeholder variables for copying the arguments that have been passed to
  * BL3-1 from BL2.
@@ -202,9 +226,8 @@
 	 * 256TB of RAM (48-bit PA) would require a 2MB L0 region. At the
 	 * moment we use a 8KB table, which covers 1TB of RAM (40-bit PA).
 	 */
-	if (gpt_init_l0_tables(PLATFORM_GPCCR_PPS, PLAT_QEMU_L0_GPT_BASE,
-			       PLAT_QEMU_L0_GPT_SIZE +
-			       PLAT_QEMU_GPT_BITLOCK_SIZE) < 0) {
+	if (gpt_init_l0_tables(PLAT_QEMU_GPCCR_PPS, PLAT_QEMU_L0_GPT_BASE,
+			       PLAT_QEMU_L0_GPT_SIZE) < 0) {
 		ERROR("gpt_init_l0_tables() failed!\n");
 		panic();
 	}
@@ -260,7 +283,7 @@
 	 * stage, so there is no need to provide any PAS here. This function
 	 * sets up pointers to those tables.
 	 */
-	if (gpt_runtime_init() < 0) {
+	if (gpt_runtime_init(BITLOCK_BASE, BITLOCK_SIZE) < 0) {
 		ERROR("gpt_runtime_init() failed!\n");
 		panic();
 	}
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
index 5dc39a1..a88297d 100644
--- a/plat/qemu/common/qemu_common.c
+++ b/plat/qemu/common/qemu_common.c
@@ -233,7 +233,7 @@
 	return 1;
 }
 
-static void plat_get_memory_node(int index, struct ns_dram_bank *bank_ptr)
+static void plat_get_memory_node(int index, struct memory_bank *bank_ptr)
 {
 	(void) index;
 	bank_ptr->base = NS_DRAM0_BASE;
@@ -245,7 +245,7 @@
 	return sbsa_platform_num_memnodes();
 }
 
-static void plat_get_memory_node(int index, struct ns_dram_bank *bank_ptr)
+static void plat_get_memory_node(int index, struct memory_bank *bank_ptr)
 {
 	struct platform_memory_data data = {0, 0, 0};
 
@@ -281,7 +281,7 @@
 	uint64_t checksum;
 	size_t num_banks = plat_get_num_memnodes();
 	size_t num_consoles = 1;
-	struct ns_dram_bank *bank_ptr;
+	struct memory_bank *bank_ptr;
 	struct console_info *console_ptr;
 
 	assert(manifest != NULL);
@@ -333,7 +333,7 @@
 	 * |   120    |  flags       |              |
 	 * +----------+--------------+--------------+
 	 */
-	bank_ptr = (struct ns_dram_bank *)
+	bank_ptr = (struct memory_bank *)
 		(((uintptr_t)manifest) + sizeof(*manifest));
 
 	console_ptr = (struct console_info *)
@@ -345,7 +345,7 @@
 	/* Ensure the manifest is not larger than the shared buffer */
 	assert((sizeof(struct rmm_manifest) +
 		(sizeof(struct console_info) * num_consoles) +
-		(sizeof(struct ns_dram_bank) * num_banks)) <= RMM_SHARED_SIZE);
+		(sizeof(struct memory_bank) * num_banks)) <= RMM_SHARED_SIZE);
 
 	/* Calculate checksum of plat_dram structure */
 	checksum = num_banks + (uint64_t)bank_ptr;
diff --git a/plat/qemu/common/qemu_pm.c b/plat/qemu/common/qemu_pm.c
index 5f64d70..7893c81 100644
--- a/plat/qemu/common/qemu_pm.c
+++ b/plat/qemu/common/qemu_pm.c
@@ -218,7 +218,7 @@
 	.cpu_standby = qemu_cpu_standby,
 	.pwr_domain_on = qemu_pwr_domain_on,
 	.pwr_domain_off = qemu_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi = qemu_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = qemu_pwr_domain_pwr_down_wfi,
 	.pwr_domain_suspend = qemu_pwr_domain_suspend,
 	.pwr_domain_on_finish = qemu_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish,
diff --git a/plat/qemu/qemu/include/platform_def.h b/plat/qemu/qemu/include/platform_def.h
index 0c85b1e..7dd7dcd 100644
--- a/plat/qemu/qemu/include/platform_def.h
+++ b/plat/qemu/qemu/include/platform_def.h
@@ -342,22 +342,16 @@
  * Tables
  */
 #define PLAT_QEMU_L0_GPT_BASE		(PLAT_QEMU_L1_GPT_BASE -	\
-					 (PLAT_QEMU_L0_GPT_SIZE +	\
-					  PLAT_QEMU_GPT_BITLOCK_SIZE))
-#define PLAT_QEMU_L0_GPT_SIZE		(2 * PAGE_SIZE)
-/* Two pages so the L0 GPT is naturally aligned.  */
-#define PLAT_QEMU_GPT_BITLOCK_SIZE	(2 * PAGE_SIZE)
+					 PLAT_QEMU_L0_GPT_SIZE)
+#define PLAT_QEMU_L0_GPT_SIZE		SZ_8K
 
 #define PLAT_QEMU_L1_GPT_BASE		(SEC_DRAM_BASE + SEC_DRAM_SIZE - \
 					 PLAT_QEMU_L1_GPT_SIZE)
-#define PLAT_QEMU_L1_GPT_END		(PLAT_QEMU_L1_GPT_BASE +	\
-					 PLAT_QEMU_L1_GPT_SIZE - 1U)
-#define PLAT_QEMU_L1_GPT_SIZE		UL(0x00100000)	/* 1MB */
+#define PLAT_QEMU_L1_GPT_SIZE		SZ_1M
 
 #define RME_GPT_DRAM_BASE		PLAT_QEMU_L0_GPT_BASE
 #define RME_GPT_DRAM_SIZE		(PLAT_QEMU_L1_GPT_SIZE +	\
-					 PLAT_QEMU_L0_GPT_SIZE +	\
-					 PLAT_QEMU_GPT_BITLOCK_SIZE)
+					 PLAT_QEMU_L0_GPT_SIZE)
 
 #ifndef __ASSEMBLER__
 /* L0 table greater than 4KB must be naturally aligned */
@@ -379,8 +373,7 @@
 
 #define MAP_GPT_L0_REGION	MAP_REGION_FLAT(			\
 					PLAT_QEMU_L0_GPT_BASE,		\
-					PLAT_QEMU_L0_GPT_SIZE +		\
-					PLAT_QEMU_GPT_BITLOCK_SIZE,	\
+					PLAT_QEMU_L0_GPT_SIZE,		\
 					MT_MEMORY | MT_RW | EL3_PAS)
 
 #define MAP_GPT_L1_REGION	MAP_REGION_FLAT(			\
diff --git a/plat/qemu/qemu/include/qemu_pas_def.h b/plat/qemu/qemu/include/qemu_pas_def.h
index 30934f0..379519f 100644
--- a/plat/qemu/qemu/include/qemu_pas_def.h
+++ b/plat/qemu/qemu/include/qemu_pas_def.h
@@ -103,7 +103,8 @@
 							       GPT_GPI_REALM)
 
 /* Cover 1TB with L0GTP */
-#define PLATFORM_GPCCR_PPS		GPCCR_PPS_1TB
+#define PLAT_QEMU_GPCCR_PPS		GPCCR_PPS_1TB
+#define PLAT_QEMU_PPS			SZ_1T
 
 /* GPT Configuration options */
 #define PLATFORM_L0GPTSZ		GPCCR_L0GPTSZ_30BITS
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index 70e9faf..bd75abc 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -39,10 +39,6 @@
 add-lib-optee 		:= 	yes
 endif
 
-ifeq (${TRANSFER_LIST},1)
-include lib/transfer_list/transfer_list.mk
-endif
-
 ifeq ($(NEED_BL32),yes)
 $(eval $(call add_define,QEMU_LOAD_BL32))
 endif
diff --git a/plat/qemu/qemu_sbsa/include/platform_def.h b/plat/qemu/qemu_sbsa/include/platform_def.h
index 06e8abf..85bd233 100644
--- a/plat/qemu/qemu_sbsa/include/platform_def.h
+++ b/plat/qemu/qemu_sbsa/include/platform_def.h
@@ -150,9 +150,19 @@
  */
 #define BL31_SIZE			0x400000
 #define BL31_BASE			(BL31_LIMIT - BL31_SIZE)
-#define BL31_LIMIT			(BL1_RW_BASE)
+#define BL31_LIMIT			(BL1_RW_BASE - FW_HANDOFF_SIZE)
 #define BL31_PROGBITS_LIMIT		BL1_RW_BASE
 
+#if TRANSFER_LIST
+#define FW_HANDOFF_BASE			BL31_LIMIT
+#define FW_HANDOFF_LIMIT		(FW_HANDOFF_BASE + FW_HANDOFF_SIZE)
+#define FW_HANDOFF_SIZE			0x4000
+#else
+#define FW_HANDOFF_SIZE			0
+#endif
+#if TRANSFER_LIST
+#define FW_NS_HANDOFF_BASE		(NS_IMAGE_OFFSET - FW_HANDOFF_SIZE)
+#endif
 
 /*
  * BL3-2 specific defines.
@@ -174,14 +184,14 @@
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 42)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 42)
 #if SPM_MM
-#define MAX_MMAP_REGIONS		12
-#define MAX_XLAT_TABLES			12
+#define MAX_MMAP_REGIONS		13
+#define MAX_XLAT_TABLES			13
 #elif ENABLE_RME
-#define MAX_MMAP_REGIONS		14
-#define MAX_XLAT_TABLES			14
+#define MAX_MMAP_REGIONS		15
+#define MAX_XLAT_TABLES			15
 #else
-#define MAX_MMAP_REGIONS		11
-#define MAX_XLAT_TABLES			11
+#define MAX_MMAP_REGIONS		12
+#define MAX_XLAT_TABLES			12
 #endif
 #define MAX_IO_DEVICES			3
 #define MAX_IO_HANDLES			4
@@ -405,24 +415,8 @@
  */
 #define PLAT_QEMU_L0_GPT_SIZE	(8 * PAGE_SIZE)
 #define PLAT_QEMU_L0_GPT_BASE	(PLAT_QEMU_L1_GPT_BASE - \
-				 (PLAT_QEMU_L0_GPT_SIZE + \
-				  PLAT_QEMU_GPT_BITLOCK_SIZE + \
-				  PLAT_QEMU_GPT_ALIGNMENT))
+				 PLAT_QEMU_L0_GPT_SIZE)
 
-#if RME_GPT_BITLOCK_BLOCK
-/*
- * 4TB / (RME_GPT_BITLOCK_BLOCK * 512M * 8) == 1024
- */
-#define PLAT_QEMU_GPT_BITLOCK_SIZE	(1 * PAGE_SIZE)
-/*
- * PLAT_QEMU_L0_GPT_SIZE is 8 pages and PLAT_QEMU_GPT_BITLOCK_SIZE
- * is 1 page.  As such we need 7 pages to have an 8 page alignment.
- */
-#define PLAT_QEMU_GPT_ALIGNMENT		(7 * PAGE_SIZE)
-#else /* RME_GPT_BITLOCK_BLOCK */
-#define PLAT_QEMU_GPT_BITLOCK_SIZE	0
-#define PLAT_QEMU_GPT_ALIGNMENT		0
-#endif /* RME_GPT_BITLOCK_BLOCK */
 
 /*
  * If we have 1TB of RAM and each L1GPT covers 1GB, we need 1024 L1GPTs. With
@@ -433,14 +427,10 @@
 #define PLAT_QEMU_L1_GPT_SIZE	UL(0x08020000)
 #define PLAT_QEMU_L1_GPT_BASE	(BL_RAM_BASE + BL_RAM_SIZE - \
 				 PLAT_QEMU_L1_GPT_SIZE)
-#define PLAT_QEMU_L1_GPT_END	(PLAT_QEMU_L1_GPT_BASE + \
-				 PLAT_QEMU_L1_GPT_SIZE - 1U)
 
 #define RME_GPT_DRAM_BASE	PLAT_QEMU_L0_GPT_BASE
 #define RME_GPT_DRAM_SIZE	(PLAT_QEMU_L1_GPT_SIZE + \
-				 PLAT_QEMU_L0_GPT_SIZE + \
-				 PLAT_QEMU_GPT_BITLOCK_SIZE + \
-				 PLAT_QEMU_GPT_ALIGNMENT)
+				 PLAT_QEMU_L0_GPT_SIZE)
 
 #ifndef __ASSEMBLER__
 /* L0 table greater than 4KB must be naturally aligned */
@@ -462,9 +452,7 @@
 
 #define MAP_GPT_L0_REGION		MAP_REGION_FLAT(		\
 					PLAT_QEMU_L0_GPT_BASE,		\
-					(PLAT_QEMU_L0_GPT_SIZE +	\
-					 PLAT_QEMU_GPT_BITLOCK_SIZE +	\
-					 PLAT_QEMU_GPT_ALIGNMENT),	\
+					(PLAT_QEMU_L0_GPT_SIZE),	\
 					MT_MEMORY | MT_RW | EL3_PAS)
 
 #define MAP_GPT_L1_REGION		MAP_REGION_FLAT(		\
diff --git a/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h b/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h
index c73a162..cf43a78 100644
--- a/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h
+++ b/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h
@@ -58,7 +58,8 @@
 					       GPT_GPI_REALM)
 
 /* Cover 4TB with L0GTP */
-#define PLATFORM_GPCCR_PPS	GPCCR_PPS_4TB
+#define PLAT_QEMU_GPCCR_PPS	GPCCR_PPS_4TB
+#define PLAT_QEMU_PPS		SZ_4T
 
 /* GPT Configuration options */
 #define PLATFORM_L0GPTSZ	GPCCR_L0GPTSZ_30BITS
diff --git a/plat/qemu/qemu_sbsa/sbsa_pm.c b/plat/qemu/qemu_sbsa/sbsa_pm.c
index 8d1e1d4..7ce7beb 100644
--- a/plat/qemu/qemu_sbsa/sbsa_pm.c
+++ b/plat/qemu/qemu_sbsa/sbsa_pm.c
@@ -215,7 +215,7 @@
 	.cpu_standby = qemu_cpu_standby,
 	.pwr_domain_on = qemu_pwr_domain_on,
 	.pwr_domain_off = qemu_pwr_domain_off,
-	.pwr_domain_pwr_down_wfi = qemu_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = qemu_pwr_domain_pwr_down_wfi,
 	.pwr_domain_suspend = qemu_pwr_domain_suspend,
 	.pwr_domain_on_finish = qemu_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish,
diff --git a/plat/qti/common/src/qti_pm.c b/plat/qti/common/src/qti_pm.c
index 1113efc..2428126 100644
--- a/plat/qti/common/src/qti_pm.c
+++ b/plat/qti/common/src/qti_pm.c
@@ -217,6 +217,7 @@
 	/* For now just do WFI - add any target specific handling if needed */
 	psci_power_down_wfi();
 	/* We should never reach here */
+	panic();
 }
 
 static __dead2 void assert_ps_hold(void)
@@ -277,7 +278,7 @@
 	.pwr_domain_off = qti_node_power_off,
 	.pwr_domain_suspend = qti_node_suspend,
 	.pwr_domain_suspend_finish = qti_node_suspend_finish,
-	.pwr_domain_pwr_down_wfi = qti_domain_power_down_wfi,
+	.pwr_domain_pwr_down = qti_domain_power_down_wfi,
 	.system_off = qti_system_off,
 	.system_reset = qti_system_reset,
 	.get_node_hw_state = NULL,
diff --git a/plat/renesas/common/plat_pm.c b/plat/renesas/common/plat_pm.c
index 9810596..871dddc 100644
--- a/plat/renesas/common/plat_pm.c
+++ b/plat/renesas/common/plat_pm.c
@@ -302,7 +302,7 @@
 	.system_off			= rcar_system_off,
 	.system_reset			= rcar_system_reset,
 	.validate_power_state		= rcar_validate_power_state,
-	.pwr_domain_pwr_down_wfi	= rcar_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down		= rcar_pwr_domain_pwr_down_wfi,
 #if RCAR_SYSTEM_SUSPEND
 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
 #endif
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
index df51d89..e88855a 100644
--- a/plat/rockchip/common/aarch64/platform_common.c
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2013-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <assert.h>
 #include <string.h>
 
 #include <platform_def.h>
@@ -58,7 +59,18 @@
 
 unsigned int plat_get_syscnt_freq2(void)
 {
+#ifdef SYS_COUNTER_FREQ_IN_TICKS
 	return SYS_COUNTER_FREQ_IN_TICKS;
+#else
+	static int sys_counter_freq_in_hz;
+
+	if (sys_counter_freq_in_hz == 0)
+		sys_counter_freq_in_hz = read_cntfrq_el0();
+
+	assert(sys_counter_freq_in_hz != 0);
+
+	return sys_counter_freq_in_hz;
+#endif
 }
 
 void plat_cci_init(void)
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index 1e13a9e..6388c47 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -28,6 +28,9 @@
 extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
 extern uint32_t __bl31_sram_stack_start, __bl31_sram_stack_end;
 extern uint32_t __bl31_sram_text_real_end, __bl31_sram_data_real_end;
+extern uint32_t __bl31_pmusram_text_start, __bl31_pmusram_text_end;
+extern uint32_t __bl31_pmusram_data_start, __bl31_pmusram_data_end;
+extern uint32_t __bl31_pmusram_text_real_end, __bl31_pmusram_data_real_end;
 extern uint32_t __sram_incbin_start, __sram_incbin_end;
 extern uint32_t __sram_incbin_real_end;
 
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
index 68054ad..a27c755 100644
--- a/plat/rockchip/common/params_setup.c
+++ b/plat/rockchip/common/params_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -37,7 +37,7 @@
 static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
 static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE;
 static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK;
-#define FDT_BUFFER_SIZE 0x20000
+#define FDT_BUFFER_SIZE 0x60000
 static uint64_t fdt_buffer[FDT_BUFFER_SIZE / 8];
 
 void *plat_get_fdt(void)
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
index 6926887..df74033 100644
--- a/plat/rockchip/common/plat_pm.c
+++ b/plat/rockchip/common/plat_pm.c
@@ -118,11 +118,15 @@
 				const psci_power_state_t *target_state)
 {
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
 {
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 /*******************************************************************************
@@ -391,7 +395,7 @@
 	.pwr_domain_suspend = rockchip_pwr_domain_suspend,
 	.pwr_domain_on_finish = rockchip_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = rockchip_pd_pwr_down_wfi,
+	.pwr_domain_pwr_down = rockchip_pd_pwr_down_wfi,
 	.system_reset = rockchip_system_reset,
 	.system_off = rockchip_system_poweroff,
 	.validate_power_state = rockchip_validate_power_state,
diff --git a/plat/rockchip/common/scmi/rockchip_common_clock.c b/plat/rockchip/common/scmi/rockchip_common_clock.c
new file mode 100644
index 0000000..d77bde3
--- /dev/null
+++ b/plat/rockchip/common/scmi/rockchip_common_clock.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <drivers/scmi.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include <plat_private.h>
+#include <scmi_clock.h>
+
+#define MUX_ADDR_INFO			0
+#define MUX_SHIFT_INFO			1
+#define MUX_WIDTH_INFO			2
+#define DIV_ADDR_INFO			3
+#define DIV_SHIFT_INFO			4
+#define DIV_WIDTH_INFO			5
+#define GATE_ADDR_INFO			6
+#define GATE_SHIFT_INFO			7
+
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+#define abs(x) ({						\
+		long ret;					\
+		if (sizeof(x) == sizeof(long)) {		\
+			long __x = (x);				\
+			ret = (__x < 0) ? -__x : __x;		\
+		} else {					\
+			int __x = (x);				\
+			ret = (__x < 0) ? -__x : __x;		\
+		}						\
+		ret;						\
+	})
+
+static unsigned long clk_scmi_common_get_parent_rate(rk_scmi_clock_t *clock,
+						     int id)
+{
+	rk_scmi_clock_t *p_clock;
+
+	if (clock->is_dynamic_prate != 0) {
+		p_clock = rockchip_scmi_get_clock(0, clock->parent_table[id]);
+		if (p_clock == NULL)
+			return 0;
+		if ((p_clock->clk_ops != NULL) && (p_clock->clk_ops->get_rate != NULL))
+			return  p_clock->clk_ops->get_rate(p_clock);
+		else
+			return 0;
+	} else {
+		return clock->parent_table[id];
+	}
+}
+
+unsigned long clk_scmi_common_get_rate(rk_scmi_clock_t *clock)
+{
+	unsigned long parent_rate, sel, div;
+
+	sel = mmio_read_32(clock->info[MUX_ADDR_INFO]) >>
+	      clock->info[MUX_SHIFT_INFO];
+	sel = sel & (BIT(clock->info[MUX_WIDTH_INFO]) - 1);
+	div = mmio_read_32(clock->info[DIV_ADDR_INFO]) >>
+	      clock->info[DIV_SHIFT_INFO];
+	div = div & (BIT(clock->info[DIV_WIDTH_INFO]) - 1);
+	parent_rate = clk_scmi_common_get_parent_rate(clock, sel);
+
+	return parent_rate / (div + 1);
+}
+
+int clk_scmi_common_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
+{
+	unsigned long parent_rate, now, best_rate = 0;
+	int i = 0, sel_mask, div_mask, best_sel = 0, best_div = 0, div;
+
+	if ((rate == 0) ||
+	    (clock->info[MUX_WIDTH_INFO] == 0 && clock->info[DIV_WIDTH_INFO] == 0))
+		return SCMI_INVALID_PARAMETERS;
+
+	sel_mask = BIT(clock->info[MUX_WIDTH_INFO]) - 1;
+	div_mask = BIT(clock->info[DIV_WIDTH_INFO]) - 1;
+	if (clock->info[MUX_WIDTH_INFO] == 0) {
+		parent_rate = clk_scmi_common_get_parent_rate(clock, 0);
+		div = DIV_ROUND_UP(parent_rate, rate);
+		if (div > div_mask + 1)
+			div = div_mask + 1;
+		mmio_write_32(clock->info[DIV_ADDR_INFO],
+			      BITS_WITH_WMASK(div - 1, div_mask,
+					      clock->info[DIV_SHIFT_INFO]));
+	} else if (clock->info[DIV_WIDTH_INFO] == 0) {
+		for (i = 0; i <= sel_mask; i++) {
+			parent_rate = clk_scmi_common_get_parent_rate(clock, i);
+			now = parent_rate;
+			if (abs(rate - now) < abs(rate - best_rate)) {
+				best_rate = now;
+				best_sel = i;
+			}
+		}
+		if (best_rate == 0)
+			best_sel = 0;
+		mmio_write_32(clock->info[MUX_ADDR_INFO],
+			      BITS_WITH_WMASK(best_sel, sel_mask,
+					      clock->info[MUX_SHIFT_INFO]));
+	} else {
+		for (i = 0; i <= sel_mask; i++) {
+			parent_rate = clk_scmi_common_get_parent_rate(clock, i);
+			div = DIV_ROUND_UP(parent_rate, rate);
+			if (div > div_mask + 1)
+				div = div_mask + 1;
+			now = parent_rate / div;
+			if (abs(rate - now) < abs(rate - best_rate)) {
+				best_rate = now;
+				best_div = div;
+				best_sel = i;
+			}
+		}
+		if (best_rate == 0) {
+			best_div = div_mask + 1;
+			best_sel = 0;
+		}
+
+		mmio_write_32(clock->info[DIV_ADDR_INFO],
+			      BITS_WITH_WMASK(div_mask, div_mask,
+					      clock->info[DIV_SHIFT_INFO]));
+		mmio_write_32(clock->info[MUX_ADDR_INFO],
+			      BITS_WITH_WMASK(best_sel, sel_mask,
+					      clock->info[MUX_SHIFT_INFO]));
+		mmio_write_32(clock->info[DIV_ADDR_INFO],
+			      BITS_WITH_WMASK(best_div - 1, div_mask,
+					      clock->info[DIV_SHIFT_INFO]));
+	}
+	return 0;
+}
+
+int clk_scmi_common_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	mmio_write_32(clock->info[GATE_ADDR_INFO],
+		      BITS_WITH_WMASK(!status, 0x1U,
+				      clock->info[GATE_SHIFT_INFO]));
+
+	return 0;
+}
diff --git a/plat/rockchip/common/scmi/scmi_clock.h b/plat/rockchip/common/scmi/scmi_clock.h
index e640fe1..4b94adf 100644
--- a/plat/rockchip/common/scmi/scmi_clock.h
+++ b/plat/rockchip/common/scmi/scmi_clock.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
+ * Copyright (c) 2025, Rockchip, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -23,11 +23,14 @@
 	char name[SCMI_CLOCK_NAME_LENGTH_MAX];
 	uint8_t enable;
 	int8_t is_security;
+	int8_t is_dynamic_prate;
 	uint32_t id;
 	uint32_t rate_cnt;
 	uint64_t cur_rate;
 	uint32_t enable_count;
 	const struct rk_clk_ops *clk_ops;
+	const unsigned long *parent_table;
+	const uint32_t *info;
 	unsigned long *rate_table;
 } rk_scmi_clock_t;
 
@@ -47,4 +50,7 @@
 rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id,
 					 uint32_t scmi_id);
 
+unsigned long clk_scmi_common_get_rate(rk_scmi_clock_t *clock);
+int clk_scmi_common_set_rate(rk_scmi_clock_t *clock, unsigned long rate);
+int clk_scmi_common_set_status(rk_scmi_clock_t *clock, bool status);
 #endif /* RK_SCMI_CLOCK_H */
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.c b/plat/rockchip/px30/drivers/pmu/pmu.c
index 0d8e8b6..6200cac 100644
--- a/plat/rockchip/px30/drivers/pmu/pmu.c
+++ b/plat/rockchip/px30/drivers/pmu/pmu.c
@@ -1000,6 +1000,8 @@
 	 * so we do not hope the core to execute valid codes.
 	 */
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 void __dead2 rockchip_soc_system_off(void)
@@ -1025,6 +1027,8 @@
 	 * so we do not hope the core to execute valid codes.
 	 */
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 void rockchip_plat_mmu_el3(void)
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.c b/plat/rockchip/rk3328/drivers/pmu/pmu.c
index 597db97..41660e2 100644
--- a/plat/rockchip/rk3328/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.c
@@ -619,6 +619,8 @@
 
 	/* should never reach here */
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 int rockchip_soc_sys_pwr_dm_suspend(void)
diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h
index ba83242..8d6ecfb 100644
--- a/plat/rockchip/rk3399/rk3399_def.h
+++ b/plat/rockchip/rk3399/rk3399_def.h
@@ -17,7 +17,7 @@
 /**************************************************************************
  * UART related constants
  **************************************************************************/
-#define RK3399_BAUDRATE			115200
+#define RK3399_BAUDRATE			1500000
 #define RK3399_UART_CLOCK		24000000
 
 /******************************************************************************
diff --git a/plat/rockchip/rk3576/drivers/dmc/dmc_rk3576.h b/plat/rockchip/rk3576/drivers/dmc/dmc_rk3576.h
new file mode 100644
index 0000000..d8c231c
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/dmc/dmc_rk3576.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __PLAT_ROCKCHIP_DMC_RK3576_H__
+#define __PLAT_ROCKCHIP_DMC_RK3576_H__
+
+#define MAX_CH_NUM			(2)
+#define CTL_PORT_NUM			(5)
+
+/* DDR_GRF Register */
+#define GRF_CH_CON(ch, n)		((((ch) % 2) * 0x100) + ((n) * 4))
+#define DDR_GRF_CH_STATUS16(ch)		(0x220 + ((ch) * 0x100))
+#define GRF_DDRPHY_CON(n)		(0x530 + ((n) * 4))
+#define GRF_DDRPHY_CON0(ch)		(0x530 + (((ch) % 2) * 0x4))
+#define DDR_GRF_COMMON_CON(n)		(0x540 + ((n) * 4))
+
+/* PMUGRF Register */
+#define PMUGRF_OS_REG(n)		(0x200 + ((n) * 4))
+
+struct low_power_st {
+	uint32_t pwrctl;
+	uint32_t clkgatectl;
+	uint32_t dfi_lp_mode_apb;
+	uint32_t grf_ddr_con0;
+	uint32_t grf_ddr_con1;
+	uint32_t grf_ddr_con6;
+	uint32_t grf_ddr_con7;
+	uint32_t grf_ddr_con9;
+	uint32_t grf_ddrphy_con0;
+	uint32_t hwlp_0;
+	uint32_t hwlp_c;
+	uint32_t pcl_pd;
+};
+
+struct rk3576_dmc_config {
+	struct low_power_st low_power[MAX_CH_NUM];
+};
+
+void dmc_save(void);
+void dmc_restore(void);
+
+#endif /* __PLAT_ROCKCHIP_DMC_RK3576_H__ */
diff --git a/plat/rockchip/rk3576/drivers/dmc/suspend.c b/plat/rockchip/rk3576/drivers/dmc/suspend.c
new file mode 100644
index 0000000..389cc1b
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/dmc/suspend.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+
+#include <dmc_rk3576.h>
+#include <rk3576_def.h>
+#include <soc.h>
+
+struct rk3576_dmc_config dmc_config;
+
+/* DDR_PHY */
+#define LP_CON0				0x0018
+#define DFI_LP_CON0			0x0e04
+/* DDR_CTL */
+#define DDRCTL_STAT			0x10014
+#define DDRCTL_PWRCTL			0x10180
+#define DDRCTL_CLKGATECTL		0x1018c
+
+/* LP_CON0 */
+#define DS_IO_PD			BIT(14)
+#define SCHD_HW_CLOCK_GATING_DISABLE	BIT(13)
+#define PCL_PD				BIT(12)
+#define DQS_ENABLE			BIT(10)
+#define WCK_ENABLE			BIT(9)
+#define CTRL_DQS_DRV_OFF		BIT(8)
+#define CTRL_SCHEDULER_EN		BIT(6)
+
+/* DFI_LP_CON0 0x0e04 */
+#define DFI_LP_MODE_APB			BIT(31)
+
+/* DDRCTL_STAT 0x10014 */
+#define CTL_SELFREF_STATE_SHIFT		(12)
+#define CTL_SELFREF_STATE_MASK		(0x7 << CTL_SELFREF_STATE_SHIFT)
+#define CTL_NOT_IN_SELF_REFRESH		(0x0 << CTL_SELFREF_STATE_SHIFT)
+#define CTL_SELF_REFRESH_1		(0x1 << CTL_SELFREF_STATE_SHIFT)
+#define CTL_SELF_REFRESH_POWER_DOWN	(0x2 << CTL_SELFREF_STATE_SHIFT)
+#define CTL_SELF_REFRESH_2		(0x3 << CTL_SELFREF_STATE_SHIFT)
+#define CTL_SELF_REFRESH_DEEP_SLEEP	(0x4 << CTL_SELFREF_STATE_SHIFT)
+#define CTL_SELFREF_TYPE_SHIFT		(4)
+#define CTL_SELFREF_TYPE_MASK		(0x3 << CTL_SELFREF_TYPE_SHIFT)
+#define CTL_SELFREF_NOT_BY_PHY		(0x1 << CTL_SELFREF_TYPE_SHIFT)
+#define CTL_SELFREF_NOT_BY_AUTO		(0x2 << CTL_SELFREF_TYPE_SHIFT)
+#define CTL_SELFREF_BY_AUTO		(0x3 << CTL_SELFREF_TYPE_SHIFT)
+#define CTL_OPERATING_MODE_MASK		(0x7)
+#define CTL_OPERATING_MODE_INIT		(0x0)
+#define CTL_OPERATING_MODE_NORMAL	(0x1)
+#define CTL_OPERATING_MODE_PD		(0x2)
+#define CTL_OPERATING_MODE_SR_SRPD	(0x3)
+
+/* DDRCTL_PWRCTL 0x10180 */
+#define CTL_DSM_EN			BIT(18)
+#define CTL_STAY_IN_SELFREF		BIT(15)
+#define CTL_SELFREF_SW			BIT(11)
+#define CTL_EN_DFI_DRAM_CLK_DISABLE	BIT(9)
+#define CTL_POWERDOWN_EN_MASK		(0xf)
+#define CTL_POWERDOWN_EN_SHIFT		(4)
+#define CTL_SELFREF_EN_MASK		(0xf)
+#define CTL_SELFREF_EN_SHIFT		(0)
+
+#define SYS_REG_DEC_CHINFO(n, ch)	(((n) >> (28 + (ch))) & 0x1)
+#define SYS_REG_DEC_CHINFO_V3(reg2, ch) SYS_REG_DEC_CHINFO(reg2, ch)
+
+#define SYS_REG_DEC_NUM_CH(n)		(1 + (((n) >> 12) & 0x1))
+#define SYS_REG_DEC_NUM_CH_V3(reg2)	SYS_REG_DEC_NUM_CH(reg2)
+
+static void exit_low_power(uint32_t ch, struct rk3576_dmc_config *configs)
+{
+	/* LP_CON0: [12]pcl_pd */
+	configs->low_power[ch].pcl_pd = mmio_read_32(DDRPHY_BASE_CH(0) + LP_CON0) & PCL_PD;
+	mmio_clrbits_32(DDRPHY_BASE_CH(ch) + LP_CON0, PCL_PD);
+
+	/* Disable low power activities */
+	configs->low_power[ch].pwrctl = mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL);
+	mmio_clrbits_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL,
+			CTL_DSM_EN | (CTL_POWERDOWN_EN_MASK << CTL_POWERDOWN_EN_SHIFT) |
+			(CTL_SELFREF_EN_MASK << CTL_SELFREF_EN_SHIFT));
+	while ((mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_STAT) & CTL_OPERATING_MODE_MASK) !=
+		CTL_OPERATING_MODE_NORMAL)
+		continue;
+
+	/* DDR_GRF_CHA_CON6: [6:0]rd_lat_delay, [14:8]wr_lat_delay, [15]cmd_dly_eq0_en */
+	configs->low_power[ch].grf_ddr_con6 =
+		mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6)) & 0xff7f;
+	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6), (0x1ul << (15 + 16)));
+
+	/* DDR_GRF_CHA_CON0: [12:8]ddrctl_axi_cg_en */
+	configs->low_power[ch].grf_ddr_con0 =
+		mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0)) & 0x1f00;
+	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0), 0x1f000000);
+
+	/*
+	 * DDR_GRF_CHA_CON1:
+	 * [15]ddrctl_apb_pclk_cg_en, [12]ddrmon_pclk_cg_en, [7]dfi_scramble_cg_en,
+	 * [6]ddrctl_mem_cg_en, [5]bsm_clk_cg_en, [2]ddrctl_core_cg_en, [1]ddrctl_apb_cg_en
+	 */
+	configs->low_power[ch].grf_ddr_con1 =
+		mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1)) & 0x90e6;
+	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1), 0x90e60000);
+
+	configs->low_power[ch].hwlp_0 = mmio_read_32(HWLP_BASE_CH(ch) + 0x0);
+	mmio_write_32(HWLP_BASE_CH(ch) + 0x0, 0x0);
+	configs->low_power[ch].hwlp_c = mmio_read_32(HWLP_BASE_CH(ch) + 0xc);
+	mmio_write_32(HWLP_BASE_CH(ch) + 0xc, 0x0);
+
+	/* DDR_GRF_CHA_PHY_CON0: [14]ddrphy_pclk_cg_en */
+	configs->low_power[ch].grf_ddrphy_con0 =
+		mmio_read_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch)) & BIT(14);
+	mmio_write_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch), BIT(14 + 16));
+
+	/* CLKGATECTL: [5:0]bsm_clk_on */
+	configs->low_power[ch].clkgatectl =
+		mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_CLKGATECTL) & 0x3f;
+	/* DFI_LP_CON0: [31]dfi_lp_mode_apb */
+	configs->low_power[ch].dfi_lp_mode_apb =
+		(mmio_read_32(DDRPHY_BASE_CH(ch) + DFI_LP_CON0) >> 31) & 0x1;
+}
+
+static void resume_low_power(uint32_t ch, struct rk3576_dmc_config *configs)
+{
+	/* DFI_LP_CON0: [31]dfi_lp_mode_apb */
+	if (configs->low_power[ch].dfi_lp_mode_apb != 0)
+		mmio_setbits_32(DDRPHY_BASE_CH(ch) + DFI_LP_CON0, DFI_LP_MODE_APB);
+
+	/* CLKGATECTL: [5:0]bsm_clk_on */
+	mmio_clrsetbits_32(UMCTL_BASE_CH(ch) + DDRCTL_CLKGATECTL,
+			   0x3f, configs->low_power[ch].clkgatectl & 0x3f);
+
+	/* DDR_GRF_CHA_CON6: [6:0]rd_lat_delay, [14:8]wr_lat_delay, [15]cmd_dly_eq0_en */
+	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6),
+		      (0xff7ful << 16) | configs->low_power[ch].grf_ddr_con6);
+
+	mmio_write_32(HWLP_BASE_CH(ch) + 0xc, configs->low_power[ch].hwlp_c);
+	mmio_write_32(HWLP_BASE_CH(ch) + 0x0, configs->low_power[ch].hwlp_0);
+
+	/* DDR_GRF_CHA_CON0: [12:8]ddrctl_axi_cg_en */
+	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0),
+		      (0x1f00ul << 16) | configs->low_power[ch].grf_ddr_con0);
+
+	/*
+	 * DDR_GRF_CHA_CON1:
+	 * [15]ddrctl_apb_pclk_cg_en, [12]ddrmon_pclk_cg_en, [7]dfi_scramble_cg_en,
+	 * [6]ddrctl_mem_cg_en, [5]bsm_clk_cg_en, [2]ddrctl_core_cg_en, [1]ddrctl_apb_cg_en
+	 */
+	mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1),
+		      (0x90e6ul << 16) | configs->low_power[ch].grf_ddr_con1);
+
+	/* DDR_GRF_CHA_PHY_CON0: [14]ddrphy_pclk_cg_en */
+	mmio_write_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch),
+		      BIT(14 + 16) | configs->low_power[ch].grf_ddrphy_con0);
+
+	/* reset low power activities */
+	mmio_write_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL, configs->low_power[ch].pwrctl);
+
+	/* LP_CON0: [12]pcl_pd */
+	if (configs->low_power[ch].pcl_pd != 0)
+		mmio_setbits_32(DDRPHY_BASE_CH(ch) + LP_CON0, PCL_PD);
+}
+
+void dmc_save(void)
+{
+	uint32_t i, channel_num;
+
+	channel_num =
+		SYS_REG_DEC_NUM_CH_V3(mmio_read_32(PMU1_GRF_BASE + PMUGRF_OS_REG(2)));
+
+	for (i = 0; i < channel_num; i++)
+		exit_low_power(i, &dmc_config);
+}
+
+void dmc_restore(void)
+{
+	uint32_t i, channel_num;
+
+	channel_num = SYS_REG_DEC_NUM_CH_V3(mmio_read_32(PMU1_GRF_BASE + PMUGRF_OS_REG(2)));
+
+	for (i = 0; i < channel_num; i++)
+		resume_low_power(i, &dmc_config);
+}
diff --git a/plat/rockchip/rk3576/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3576/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..717b55c
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.globl	clst_warmboot_data
+
+.macro	func_rockchip_clst_warmboot
+.endm
+
+.macro rockchip_clst_warmboot_data
+clst_warmboot_data:
+	.rept	PLATFORM_CLUSTER_COUNT
+	.word	0
+	.endr
+.endm
diff --git a/plat/rockchip/rk3576/drivers/pmu/pm_pd_regs.c b/plat/rockchip/rk3576/drivers/pmu/pm_pd_regs.c
new file mode 100644
index 0000000..de5fa75
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/pmu/pm_pd_regs.c
@@ -0,0 +1,451 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <pmu.h>
+
+#include <plat_pm_helpers.h>
+#include <plat_private.h>
+#include <pm_pd_regs.h>
+#include <rk3576_clk.h>
+#include <soc.h>
+
+#define WMSK_VAL		0xffff0000
+
+static struct reg_region qos_reg_rgns[] = {
+	[qos_decom] = REG_REGION(0x08, 0x18, 4, 0x27f00000, 0),
+	[qos_dmac0] = REG_REGION(0x08, 0x18, 4, 0x27f00080, 0),
+	[qos_dmac1] = REG_REGION(0x08, 0x18, 4, 0x27f00100, 0),
+	[qos_dmac2] = REG_REGION(0x08, 0x18, 4, 0x27f00180, 0),
+	[qos_bus_mcu] = REG_REGION(0x08, 0x18, 4, 0x27f00200, 0),
+	[qos_can0] = REG_REGION(0x08, 0x18, 4, 0x27f00280, 0),
+	[qos_can1] = REG_REGION(0x08, 0x18, 4, 0x27f00300, 0),
+	[qos_cci_m0] = REG_REGION(0x08, 0x18, 4, 0x27f01000, 0),
+	[qos_cci_m1] = REG_REGION(0x08, 0x18, 4, 0x27f18880, 0),
+	[qos_cci_m2] = REG_REGION(0x08, 0x18, 4, 0x27f18900, 0),
+	[qos_dap_lite] = REG_REGION(0x08, 0x18, 4, 0x27f01080, 0),
+	[qos_hdcp1] = REG_REGION(0x08, 0x18, 4, 0x27f02000, 0),
+	[qos_ddr_mcu] = REG_REGION(0x08, 0x18, 4, 0x27f03000, 0),
+	[qos_fspi1] = REG_REGION(0x08, 0x18, 4, 0x27f04000, 0),
+	[qos_gmac0] = REG_REGION(0x08, 0x18, 4, 0x27f04080, 0),
+	[qos_gmac1] = REG_REGION(0x08, 0x18, 4, 0x27f04100, 0),
+	[qos_sdio] = REG_REGION(0x08, 0x18, 4, 0x27f04180, 0),
+	[qos_sdmmc] = REG_REGION(0x08, 0x18, 4, 0x27f04200, 0),
+	[qos_flexbus] = REG_REGION(0x08, 0x18, 4, 0x27f04280, 0),
+	[qos_gpu] = REG_REGION(0x08, 0x18, 4, 0x27f05000, 0),
+	[qos_vepu1] = REG_REGION(0x08, 0x18, 4, 0x27f06000, 0),
+	[qos_npu_mcu] = REG_REGION(0x08, 0x18, 4, 0x27f08000, 0),
+	[qos_npu_nsp0] = REG_REGION(0x08, 0x18, 4, 0x27f08080, 0),
+	[qos_npu_nsp1] = REG_REGION(0x08, 0x18, 4, 0x27f08100, 0),
+	[qos_npu_m0] = REG_REGION(0x08, 0x18, 4, 0x27f20000, 0),
+	[qos_npu_m1] = REG_REGION(0x08, 0x18, 4, 0x27f21000, 0),
+	[qos_npu_m0ro] = REG_REGION(0x08, 0x18, 4, 0x27f22080, 0),
+	[qos_npu_m1ro] = REG_REGION(0x08, 0x18, 4, 0x27f22100, 0),
+	[qos_emmc] = REG_REGION(0x08, 0x18, 4, 0x27f09000, 0),
+	[qos_fspi0] = REG_REGION(0x08, 0x18, 4, 0x27f09080, 0),
+	[qos_mmu0] = REG_REGION(0x08, 0x18, 4, 0x27f0a000, 0),
+	[qos_mmu1] = REG_REGION(0x08, 0x18, 4, 0x27f0a080, 0),
+	[qos_pmu_mcu] = REG_REGION(0x08, 0x18, 4, 0x27f0b000, 0),
+	[qos_rkvdec] = REG_REGION(0x08, 0x18, 4, 0x27f0c000, 0),
+	[qos_crypto] = REG_REGION(0x08, 0x18, 4, 0x27f0d000, 0),
+	[qos_mmu2] = REG_REGION(0x08, 0x18, 4, 0x27f0e000, 0),
+	[qos_ufshc] = REG_REGION(0x08, 0x18, 4, 0x27f0e080, 0),
+	[qos_vepu0] = REG_REGION(0x08, 0x18, 4, 0x27f0f000, 0),
+	[qos_isp_mro] = REG_REGION(0x08, 0x18, 4, 0x27f10000, 0),
+	[qos_isp_mwo] = REG_REGION(0x08, 0x18, 4, 0x27f10080, 0),
+	[qos_vicap_m0] = REG_REGION(0x08, 0x18, 4, 0x27f10100, 0),
+	[qos_vpss_mro] = REG_REGION(0x08, 0x18, 4, 0x27f10180, 0),
+	[qos_vpss_mwo] = REG_REGION(0x08, 0x18, 4, 0x27f10200, 0),
+	[qos_hdcp0] = REG_REGION(0x08, 0x18, 4, 0x27f11000, 0),
+	[qos_vop_m0] = REG_REGION(0x08, 0x18, 4, 0x27f12800, 0),
+	[qos_vop_m1ro] = REG_REGION(0x08, 0x18, 4, 0x27f12880, 0),
+	[qos_ebc] = REG_REGION(0x08, 0x18, 4, 0x27f13000, 0),
+	[qos_rga0] = REG_REGION(0x08, 0x18, 4, 0x27f13080, 0),
+	[qos_rga1] = REG_REGION(0x08, 0x18, 4, 0x27f13100, 0),
+	[qos_jpeg] = REG_REGION(0x08, 0x18, 4, 0x27f13180, 0),
+	[qos_vdpp] = REG_REGION(0x08, 0x18, 4, 0x27f13200, 0),
+	[qos_dma2ddr] = REG_REGION(0x08, 0x18, 4, 0x27f15880, 0),
+};
+
+static struct reg_region pd_bcore_reg_rgns[] = {
+	/* bcore cru */
+	/* REG_REGION(0x280, 0x280, 4, BIGCORE0CRU_BASE, WMSK_VAL), */
+	REG_REGION(0x300, 0x30c, 4, BIGCORE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0x800, 0x804, 4, BIGCORE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xa00, 0xa0c, 4, BIGCORE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xcc0, 0xcc0, 4, BIGCORE_CRU_BASE, 0),
+	REG_REGION(0xf28, 0xf28, 8, BIGCORE_CRU_BASE, 0),
+	REG_REGION(0xf2c, 0xf2c, 8, BIGCORE_CRU_BASE, WMSK_VAL),
+
+	/* bcore_grf */
+	REG_REGION(0x34, 0x3c, 4, BIGCORE_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x44, 0x44, 4, BIGCORE_GRF_BASE, WMSK_VAL),
+};
+
+static struct reg_region pd_core_reg_rgns[] = {
+	/* cci cru */
+	REG_REGION(0x310, 0x310, 4, CCI_CRU_BASE, WMSK_VAL),
+	REG_REGION(0x804, 0x808, 4, CCI_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xa04, 0xa08, 4, CCI_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xc50, 0xc58, 4, CCI_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xd00, 0xd00, 8, CCI_CRU_BASE, 0),
+	REG_REGION(0xd04, 0xd04, 8, CCI_CRU_BASE, WMSK_VAL),
+	/* Restore lpll registers after clksel_* registers. Because lpll
+	 * may be turned off during restoring, which cause cci_cru to lost clock.
+	 */
+	REG_REGION(0x040, 0x044, 4, CCI_CRU_BASE, WMSK_VAL),
+	REG_REGION(0x048, 0x048, 4, CCI_CRU_BASE, 0),
+	REG_REGION(0x04c, 0x058, 4, CCI_CRU_BASE, WMSK_VAL),
+
+	/* lcore cru */
+	/* REG_REGION(0x280, 0x280, 4, BIGCORE1CRU_BASE, WMSK_VAL), */
+	REG_REGION(0x300, 0x30c, 4, LITTLE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0x800, 0x804, 4, LITTLE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xa00, 0xa0c, 4, LITTLE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xcc0, 0xcc0, 4, LITTLE_CRU_BASE, 0),
+	REG_REGION(0xf38, 0xf38, 8, LITTLE_CRU_BASE, 0),
+	REG_REGION(0xf3c, 0xf3c, 8, LITTLE_CRU_BASE, WMSK_VAL),
+
+	/* bcore cru */
+	/* REG_REGION(0x280, 0x280, 4, BIGCORE0CRU_BASE, WMSK_VAL), */
+	REG_REGION(0x300, 0x30c, 4, BIGCORE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0x800, 0x804, 4, BIGCORE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xa00, 0xa0c, 4, BIGCORE_CRU_BASE, WMSK_VAL),
+	REG_REGION(0xcc0, 0xcc0, 4, BIGCORE_CRU_BASE, 0),
+	REG_REGION(0xf28, 0xf28, 8, BIGCORE_CRU_BASE, 0),
+	REG_REGION(0xf2c, 0xf2c, 8, BIGCORE_CRU_BASE, WMSK_VAL),
+
+	/* cci grf */
+	REG_REGION(0x00, 0x10, 4, CCI_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x54, 0x54, 4, CCI_GRF_BASE, WMSK_VAL),
+
+	/* lcore_grf */
+	REG_REGION(0x34, 0x3c, 4, LITCORE_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x44, 0x44, 4, LITCORE_GRF_BASE, WMSK_VAL),
+
+	/* bcore_grf */
+	REG_REGION(0x34, 0x3c, 4, BIGCORE_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x44, 0x44, 4, BIGCORE_GRF_BASE, WMSK_VAL),
+};
+
+static struct reg_region pd_php_reg_rgns[] = {
+	/* php_grf */
+	REG_REGION(0x004, 0x00c, 4, PHP_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x010, 0x018, 4, PHP_GRF_BASE, 0),
+	REG_REGION(0x01c, 0x020, 4, PHP_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x048, 0x048, 4, PHP_GRF_BASE, 0),
+};
+
+static struct reg_region pd_usb2phy_reg_rgns[] = {
+	/* usb */
+	REG_REGION(0x00, 0x14, 4, USB2PHY0_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x40, 0x40, 4, USB2PHY0_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x44, 0x50, 4, USB2PHY0_GRF_BASE, 0),
+	REG_REGION(0x00, 0x14, 4, USB2PHY1_GRF_BASE, WMSK_VAL),
+	REG_REGION(0x08, 0x08, 4, USBDPPHY_GRF_BASE, WMSK_VAL),
+};
+
+#define PLL_LOCKED_TIMEOUT 600000U
+
+static void pm_pll_wait_lock(uint32_t pll_base)
+{
+	int delay = PLL_LOCKED_TIMEOUT;
+
+	if ((mmio_read_32(pll_base + CRU_PLL_CON(1)) & CRU_PLLCON1_PWRDOWN) != 0)
+		return;
+
+	while (delay-- >= 0) {
+		if ((mmio_read_32(pll_base + CRU_PLL_CON(6)) & CRU_PLLCON6_LOCK_STATUS) != 0)
+			break;
+		udelay(1);
+	}
+
+	if (delay <= 0)
+		ERROR("Can't wait pll(0x%x) lock\n", pll_base);
+}
+
+void qos_save(void)
+{
+	uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
+
+	if ((pmu_pd_st & BIT(pmu_pd_nvm)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_emmc], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_fspi0], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_sd_gmac)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_fspi1], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_gmac0], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_gmac1], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_sdio], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_sdmmc], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_flexbus], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_php)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_mmu0], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_mmu1], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vop)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vop_m0], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vop_m1ro], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vo1)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_hdcp1], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vo0)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_hdcp0], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_usb)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_mmu2], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_ufshc], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vi)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_isp_mro], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_isp_mwo], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vicap_m0], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vpss_mro], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vpss_mwo], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vepu0)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vepu0], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vepu1)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vepu1], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vdec)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_rkvdec], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vpu)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_ebc], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_rga0], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_rga1], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_jpeg], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_vdpp], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_nputop)) == 0) {
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_mcu], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_nsp0], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_nsp1], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_m0ro], 1);
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_m1ro], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_npu0)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_m0], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_npu1)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_npu_m1], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_gpu)) == 0)
+		rockchip_reg_rgn_save(&qos_reg_rgns[qos_gpu], 1);
+}
+
+void qos_restore(void)
+{
+	uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
+
+	if ((pmu_pd_st & BIT(pmu_pd_nvm)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_emmc], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_fspi0], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_sd_gmac)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_fspi1], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_gmac0], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_gmac1], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_sdio], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_sdmmc], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_flexbus], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_php)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_mmu0], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_mmu1], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vop)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vop_m0], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vop_m1ro], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vo1)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_hdcp1], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vo0)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_hdcp0], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_usb)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_mmu2], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_ufshc], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vi)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_isp_mro], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_isp_mwo], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vicap_m0], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vpss_mro], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vpss_mwo], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_vepu0)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vepu0], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vepu1)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vepu1], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vdec)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_rkvdec], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_vpu)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_ebc], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_rga0], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_rga1], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_jpeg], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_vdpp], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_nputop)) == 0) {
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_mcu], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_nsp0], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_nsp1], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_m0ro], 1);
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_m1ro], 1);
+	}
+
+	if ((pmu_pd_st & BIT(pmu_pd_npu0)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_m0], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_npu1)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_npu_m1], 1);
+
+	if ((pmu_pd_st & BIT(pmu_pd_gpu)) == 0)
+		rockchip_reg_rgn_restore(&qos_reg_rgns[qos_gpu], 1);
+}
+
+void pd_usb2phy_save(void)
+{
+	rockchip_reg_rgn_save(pd_usb2phy_reg_rgns, ARRAY_SIZE(pd_usb2phy_reg_rgns));
+}
+
+void pd_usb2phy_restore(void)
+{
+	rockchip_reg_rgn_restore(pd_usb2phy_reg_rgns, ARRAY_SIZE(pd_usb2phy_reg_rgns));
+}
+
+static uint32_t b_cru_mode, l_cru_mode;
+static uint32_t bcore_need_restore;
+
+void pd_bcore_save(void)
+{
+	pvtplls_cpub_suspend();
+
+	b_cru_mode = mmio_read_32(BIGCORE_CRU_BASE + 0x280);
+	rockchip_reg_rgn_save(pd_bcore_reg_rgns, ARRAY_SIZE(pd_bcore_reg_rgns));
+
+	bcore_need_restore = 1;
+}
+
+void pd_bcore_restore(void)
+{
+	if (bcore_need_restore == 0)
+		return;
+
+	/* slow mode */
+	mmio_write_32(BIGCORE_CRU_BASE + 0x280, 0x00030000);
+
+	rockchip_reg_rgn_restore(pd_bcore_reg_rgns, ARRAY_SIZE(pd_bcore_reg_rgns));
+
+	/* trigger lcore/bcore mem_cfg */
+	mmio_write_32(BIGCORE_GRF_BASE + 0x38, BITS_WITH_WMASK(1, 0x1, 1));
+	udelay(1);
+	mmio_write_32(BIGCORE_GRF_BASE + 0x38, BITS_WITH_WMASK(0, 0x1, 1));
+
+	/* restore mode */
+	mmio_write_32(BIGCORE_CRU_BASE + 0x280, WITH_16BITS_WMSK(b_cru_mode));
+
+	pvtplls_cpub_resume();
+
+	bcore_need_restore = 0;
+}
+
+void pd_core_save(void)
+{
+	pvtplls_suspend();
+
+	b_cru_mode = mmio_read_32(BIGCORE_CRU_BASE + 0x280);
+	l_cru_mode = mmio_read_32(LITTLE_CRU_BASE + 0x280);
+
+	rockchip_reg_rgn_save(&qos_reg_rgns[qos_cci_m0], 1);
+	rockchip_reg_rgn_save(&qos_reg_rgns[qos_cci_m1], 1);
+	rockchip_reg_rgn_save(&qos_reg_rgns[qos_cci_m2], 1);
+	rockchip_reg_rgn_save(&qos_reg_rgns[qos_dap_lite], 1);
+
+	rockchip_reg_rgn_save(pd_core_reg_rgns, ARRAY_SIZE(pd_core_reg_rgns));
+}
+
+void pd_core_restore(void)
+{
+	/* slow mode */
+	mmio_write_32(BIGCORE_CRU_BASE + 0x280, 0x00030000);
+	mmio_write_32(LITTLE_CRU_BASE + 0x280, 0x00030000);
+
+	rockchip_reg_rgn_restore(pd_core_reg_rgns, ARRAY_SIZE(pd_core_reg_rgns));
+
+	/* trigger lcore/bcore mem_cfg */
+	mmio_write_32(LITCORE_GRF_BASE + 0x38, BITS_WITH_WMASK(1, 0x1, 1));
+	mmio_write_32(BIGCORE_GRF_BASE + 0x38, BITS_WITH_WMASK(1, 0x1, 1));
+	udelay(1);
+	mmio_write_32(LITCORE_GRF_BASE + 0x38, BITS_WITH_WMASK(0, 0x1, 1));
+	mmio_write_32(BIGCORE_GRF_BASE + 0x38, BITS_WITH_WMASK(0, 0x1, 1));
+
+	/* wait lock */
+	pm_pll_wait_lock(CCI_CRU_BASE + 0x40);
+
+	/* restore mode */
+	mmio_write_32(BIGCORE_CRU_BASE + 0x280, WITH_16BITS_WMSK(b_cru_mode));
+	mmio_write_32(LITTLE_CRU_BASE + 0x280, WITH_16BITS_WMSK(l_cru_mode));
+
+	rockchip_reg_rgn_restore(&qos_reg_rgns[qos_cci_m0], 1);
+	rockchip_reg_rgn_restore(&qos_reg_rgns[qos_cci_m1], 1);
+	rockchip_reg_rgn_restore(&qos_reg_rgns[qos_cci_m2], 1);
+	rockchip_reg_rgn_restore(&qos_reg_rgns[qos_dap_lite], 1);
+
+	pvtplls_resume();
+}
+
+void pd_php_save(void)
+{
+	rockchip_reg_rgn_save(pd_php_reg_rgns, ARRAY_SIZE(pd_php_reg_rgns));
+}
+
+void pd_php_restore(void)
+{
+	rockchip_reg_rgn_restore(pd_php_reg_rgns, ARRAY_SIZE(pd_php_reg_rgns));
+}
+
+void pm_reg_rgns_init(void)
+{
+	rockchip_alloc_region_mem(qos_reg_rgns, ARRAY_SIZE(qos_reg_rgns));
+	rockchip_alloc_region_mem(pd_bcore_reg_rgns, ARRAY_SIZE(pd_bcore_reg_rgns));
+	rockchip_alloc_region_mem(pd_core_reg_rgns, ARRAY_SIZE(pd_core_reg_rgns));
+	rockchip_alloc_region_mem(pd_php_reg_rgns, ARRAY_SIZE(pd_php_reg_rgns));
+	rockchip_alloc_region_mem(pd_usb2phy_reg_rgns, ARRAY_SIZE(pd_usb2phy_reg_rgns));
+}
diff --git a/plat/rockchip/rk3576/drivers/pmu/pm_pd_regs.h b/plat/rockchip/rk3576/drivers/pmu/pm_pd_regs.h
new file mode 100644
index 0000000..5b4f624
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/pmu/pm_pd_regs.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef PM_PD_REGS_H
+#define PM_PD_REGS_H
+
+#include <stdint.h>
+
+void qos_save(void);
+void qos_restore(void);
+void pd_usb2phy_save(void);
+void pd_usb2phy_restore(void);
+void pd_secure_save(void);
+void pd_secure_restore(void);
+void pd_bcore_save(void);
+void pd_bcore_restore(void);
+void pd_core_save(void);
+void pd_core_restore(void);
+void pd_php_save(void);
+void pd_php_restore(void);
+void pd_center_save(void);
+void pd_center_restore(void);
+void pd_bus_save(void);
+void pd_bus_restore(void);
+void pd_pmu1_save(void);
+void pd_pmu1_restore_early(void);
+void pd_pmu1_restore(void);
+void pd_pmu0_save(void);
+void pd_pmu0_restore(void);
+
+void pm_reg_rgns_init(void);
+void pm_regs_rgn_dump(void);
+
+#endif
diff --git a/plat/rockchip/rk3576/drivers/pmu/pmu.c b/plat/rockchip/rk3576/drivers/pmu/pmu.c
new file mode 100644
index 0000000..c7db176
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/pmu/pmu.c
@@ -0,0 +1,1069 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <pmu.h>
+
+#include <cpus_on_fixed_addr.h>
+#include <dmc_rk3576.h>
+#include <plat_pm_helpers.h>
+#include <plat_private.h>
+#include <pm_pd_regs.h>
+#include <secure.h>
+#include <soc.h>
+
+static struct psram_data_t *psram_sleep_cfg =
+	(struct psram_data_t *)&sys_sleep_flag_sram;
+
+struct rk3576_sleep_ddr_data {
+	uint32_t cru_mode_con, secure_cru_mode;
+	uint32_t gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l;
+	uint32_t pmu2_bisr_glb_con;
+	uint32_t pmu2_c0_ack_sel_con0, pmu2_c1_ack_sel_con0, pmu2_c2_ack_sel_con0;
+	uint32_t pmu2_fast_pwr_con, pmu2_pwrgt_sft_con0;
+	uint32_t pmu0grf_soc_con0, pmu0grf_soc_con1, pmu0grf_soc_con5;
+	uint32_t pmu_pd_st, bus_idle_st;
+	uint32_t sys_sgrf_soc_con0;
+	uint32_t ddrgrf_cha_con2, ddrgrf_chb_con2;
+};
+
+static struct rk3576_sleep_ddr_data ddr_data;
+
+void rockchip_plat_mmu_el3(void)
+{
+#ifdef PLAT_EXTRA_LD_SCRIPT
+	size_t sram_size;
+
+	sram_size = (char *)&__bl31_pmusram_text_end -
+		    (char *)PMUSRAM_BASE;
+	mmap_add_region(PMUSRAM_BASE, PMUSRAM_BASE,
+			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
+
+	sram_size = (char *)&__bl31_pmusram_data_end -
+		    (char *)&__bl31_pmusram_data_start;
+	mmap_add_region((unsigned long)&__bl31_pmusram_data_start,
+			(unsigned long)&__bl31_pmusram_data_start,
+			sram_size, MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+}
+
+static int check_cpu_wfie(uint32_t cpu)
+{
+	uint32_t loop = 0;
+
+	while ((mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0) & BIT(cpu + 12)) == 0 &&
+	       (mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & BIT(cpu)) == 0 &&
+	       (loop < WFEI_CHECK_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if (loop >= WFEI_CHECK_LOOP) {
+		WARN("%s: error, cpu%d (0x%x 0x%x)!\n", __func__, cpu,
+		     mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0),
+		     mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline uint32_t cpu_power_domain_st(uint32_t cpu)
+{
+	return !!(mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) &
+		  BIT(cpu + 16));
+}
+
+static int cpu_power_domain_ctr(uint32_t cpu, uint32_t pd_state)
+{
+	uint32_t loop = 0;
+	int ret = 0;
+
+	mmio_write_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu),
+		      BITS_WITH_WMASK(pd_state, 0x1, 0));
+
+	dsb();
+	while ((cpu_power_domain_st(cpu) != pd_state) && (loop < PD_CTR_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if (cpu_power_domain_st(cpu) != pd_state) {
+		WARN("%s: %d, %d, error!\n", __func__, cpu, pd_state);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
+{
+	uint32_t val;
+
+	if ((mmio_read_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu_id)) & BIT(0)) != 0)
+		return core_pwr_pd;
+
+	val = mmio_read_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id));
+	if ((val & BIT(pmu_cpu_pm_en)) != 0) {
+		if ((val & BIT(core_pwr_wfi_int)) != 0)
+			return core_pwr_wfi_int;
+		else if ((val & BIT(pmu_cpu_pm_sft_wakeup_en)) != 0)
+			return core_pwr_wfi_reset;
+		else
+			return core_pwr_wfi;
+	} else {
+		return -1;
+	}
+}
+
+static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
+{
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+	uint32_t cfg_info;
+	/*
+	 * There are two ways to powering on or off on core.
+	 * 1) Control it power domain into on or off in PMU_PWRDN_CON reg
+	 * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
+	 *	then, if the core enter into wfi, it power domain will be
+	 *	powered off automatically.
+	 */
+
+	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
+
+	if (cfg_info == core_pwr_pd) {
+		/* disable core_pm cfg */
+		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
+			      BITS_WITH_WMASK(0, 0xf, 0));
+		/* if the cores have be on, power off it firstly */
+		if (cpu_power_domain_st(cpu_id) == pmu_pd_on)
+			cpu_power_domain_ctr(cpu_id, pmu_pd_off);
+
+		cpu_power_domain_ctr(cpu_id, pmu_pd_on);
+	} else {
+		if (cpu_power_domain_st(cpu_id) == pmu_pd_on) {
+			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
+			return -EINVAL;
+		}
+
+		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
+			      BITS_WITH_WMASK(1, 0x1, pmu_cpu_pm_sft_wakeup_en));
+		dsb();
+	}
+
+	return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
+{
+	uint32_t core_pm_value;
+
+	if (cpu_power_domain_st(cpu_id) == pmu_pd_off)
+		return 0;
+
+	if (pd_cfg == core_pwr_pd) {
+		if (check_cpu_wfie(cpu_id))
+			return -EINVAL;
+
+		/* disable core_pm cfg */
+		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
+			      BITS_WITH_WMASK(0, 0xf, 0));
+
+		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+		cpu_power_domain_ctr(cpu_id, pmu_pd_off);
+	} else {
+		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+
+		core_pm_value = BIT(pmu_cpu_pm_en) | BIT(pmu_cpu_pm_dis_int);
+		if (pd_cfg == core_pwr_wfi_int)
+			core_pm_value |= BIT(pmu_cpu_pm_int_wakeup_en);
+		else if (pd_cfg == core_pwr_wfi_reset)
+			core_pm_value |= BIT(pmu_cpu_pm_sft_wakeup_en);
+
+		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
+			      BITS_WITH_WMASK(core_pm_value, 0xf, 0));
+		dsb();
+	}
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpu_id] = entrypoint;
+	dsb();
+
+	cpus_power_domain_on(cpu_id);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
+		      BITS_WITH_WMASK(0, 0xf, 0));
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
+	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
+	dsb();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	/* Disable core_pm */
+	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
+		      BITS_WITH_WMASK(0, 0xf, 0));
+
+	return PSCI_E_SUCCESS;
+}
+
+void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, cpu;
+
+	boot_cpu = plat_my_core_pos();
+
+	/* turn off noboot cpus */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		if (cpu == boot_cpu)
+			continue;
+
+		cpus_power_domain_off(cpu, core_pwr_pd);
+	}
+}
+
+static __pmusramfunc void ddr_resume(void)
+{
+	uint32_t key_upd_msk =
+		mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pmu_pd_vop) ? 0x3 : 0x7;
+
+	/* hptimer is 24M here */
+	write_cntfrq_el0(24000000);
+
+	/* release cpu1~cpu7 to make pmu1_fsm exit */
+	mmio_write_32(CCI_GRF_BASE + CCIGRF_CON(4), 0xffffffff);
+	mmio_write_32(LITCORE_GRF_BASE + COREGRF_CPU_CON(1),
+		      BITS_WITH_WMASK(0x77, 0xff, 4));
+
+	/* wait pmu1 fsm over */
+	while ((mmio_read_32(PMU_BASE + PMU1_PWR_FSM) & 0xf) != 0)
+		;
+
+	/* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000);
+	dsb();
+
+	/* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000 | key_upd_msk);
+
+	/* SOC_STATUS.center/cci_ddr_hash_key_shift_ready */
+	while (((mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_STATUS) >> 12) & key_upd_msk) != key_upd_msk)
+		;
+
+	/* CCI_BASE.ctrl_override_reg Attr:W1C addrmap strobe */
+	mmio_setbits_32(CCI_BASE + 0x0, 0x1 << 29);
+
+	/* SOC_CON19.vop/center/cci_ddr_hash_key_auto_update_en */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00700070);
+}
+
+static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHP_CRU_CLKGATE_CON_CNT +
+			 SECURE_CRU_CLKGATE_CON_CNT + SECURE_SCRU_CLKGATE_CON_CNT +
+			 PMU1CRU_CLKGATE_CON_CNT + PMU1SCRU_CLKGATE_CON_CNT];
+
+void clk_gate_con_disable(void)
+{
+	int i;
+
+	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++) {
+		/* Don't open wdt0 clk (cru_gate16[7:8] */
+		if (i == 16) {
+			mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
+				      0xfe7f0000);
+		} else {
+			mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
+				      0xffff0000);
+		}
+	}
+
+	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 0xffff0000);
+
+	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 0xffff0000);
+
+	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 0xffff0000);
+
+	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 0xffff0000);
+
+	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 0xffff0000);
+}
+
+void clk_gate_con_save(void)
+{
+	int i, j = 0;
+
+	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
+		clk_save[j] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
+
+	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++)
+		clk_save[j] = mmio_read_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i));
+
+	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++)
+		clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i));
+
+	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++)
+		clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i));
+
+	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
+		clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i));
+
+	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++)
+		clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i));
+}
+
+void clk_gate_con_restore(void)
+{
+	int i, j = 0;
+
+	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
+			      WITH_16BITS_WMSK(clk_save[j]));
+
+	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i),
+			      WITH_16BITS_WMSK(clk_save[j]));
+
+	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i),
+			      WITH_16BITS_WMSK(clk_save[j]));
+
+	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i),
+			      WITH_16BITS_WMSK(clk_save[j]));
+
+	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i),
+			      WITH_16BITS_WMSK(clk_save[j]));
+
+	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i),
+			      WITH_16BITS_WMSK(clk_save[j]));
+}
+
+void pmu_bus_idle_req(uint32_t bus, uint32_t state)
+{
+	uint32_t wait_cnt = 0;
+
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_SFTCON(bus / 16),
+		      BITS_WITH_WMASK(state, 0x1, bus % 16));
+
+	while (pmu_bus_idle_st(bus) != state ||
+	       pmu_bus_idle_ack(bus) != state) {
+		if (++wait_cnt > BUS_IDLE_LOOP)
+			break;
+		udelay(1);
+	}
+
+	if (wait_cnt > BUS_IDLE_LOOP)
+		WARN("%s: can't  wait state %d for bus %d (0x%x)\n",
+		     __func__, state, bus,
+		     mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST));
+}
+
+static inline uint32_t pmu_power_domain_st(uint32_t pd)
+{
+	return mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pd) ?
+	       pmu_pd_off :
+	       pmu_pd_on;
+}
+
+int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
+{
+	uint32_t loop = 0;
+	int ret = 0;
+
+	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(pd / 16),
+		      BITS_WITH_WMASK(pd_state, 0x1, pd % 16));
+	dsb();
+
+	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if (pmu_power_domain_st(pd) != pd_state) {
+		WARN("%s: %d, %d, (0x%x) error!\n", __func__, pd, pd_state,
+		     mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST));
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
+{
+	uint32_t state;
+
+	if (pmu_power_domain_st(pd_id) == pd_state)
+		goto out;
+
+	if (pd_state == pmu_pd_on)
+		pmu_power_domain_ctr(pd_id, pd_state);
+
+	state = (pd_state == pmu_pd_off) ? pmu_bus_idle : pmu_bus_active;
+
+	switch (pd_id) {
+	case pmu_pd_npu:
+		pmu_bus_idle_req(pmu_bus_id_npusys, state);
+		break;
+	case pmu_pd_secure:
+		pmu_bus_idle_req(pmu_bus_id_secure, state);
+		break;
+	case pmu_pd_nvm:
+		pmu_bus_idle_req(pmu_bus_id_nvm, state);
+		break;
+	case pmu_pd_sd_gmac:
+		pmu_bus_idle_req(pmu_bus_id_gmac, state);
+		break;
+	case pmu_pd_audio:
+		pmu_bus_idle_req(pmu_bus_id_audio, state);
+		break;
+	case pmu_pd_php:
+		pmu_bus_idle_req(pmu_bus_id_php, state);
+		break;
+	case pmu_pd_subphp:
+		break;
+	case pmu_pd_vop:
+		pmu_bus_idle_req(pmu_bus_id_vop, state);
+		break;
+	case pmu_pd_vop_smart:
+		break;
+	case pmu_pd_vop_clst:
+		break;
+	case pmu_pd_vo1:
+		pmu_bus_idle_req(pmu_bus_id_vo1, state);
+		break;
+	case pmu_pd_vo0:
+		pmu_bus_idle_req(pmu_bus_id_vo0, state);
+		break;
+	case pmu_pd_usb:
+		pmu_bus_idle_req(pmu_bus_id_usb, state);
+		break;
+	case pmu_pd_vi:
+		pmu_bus_idle_req(pmu_bus_id_vi, state);
+		break;
+	case pmu_pd_vepu0:
+		pmu_bus_idle_req(pmu_bus_id_vepu0, state);
+		break;
+	case pmu_pd_vepu1:
+		pmu_bus_idle_req(pmu_bus_id_vepu1, state);
+		break;
+	case pmu_pd_vdec:
+		pmu_bus_idle_req(pmu_bus_id_vdec, state);
+		break;
+	case pmu_pd_vpu:
+		pmu_bus_idle_req(pmu_bus_id_vpu, state);
+		break;
+	case pmu_pd_nputop:
+		pmu_bus_idle_req(pmu_bus_id_nputop, state);
+		break;
+	case pmu_pd_npu0:
+		pmu_bus_idle_req(pmu_bus_id_npu0, state);
+		break;
+	case pmu_pd_npu1:
+		pmu_bus_idle_req(pmu_bus_id_npu1, state);
+		break;
+	case pmu_pd_gpu:
+		pmu_bus_idle_req(pmu_bus_id_gpu, state);
+		break;
+	default:
+		break;
+	}
+
+	if (pd_state == pmu_pd_off)
+		pmu_power_domain_ctr(pd_id, pd_state);
+
+out:
+	return 0;
+}
+
+static void pmu_power_domains_suspend(void)
+{
+	ddr_data.pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
+	ddr_data.bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST);
+	ddr_data.pmu2_pwrgt_sft_con0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0));
+
+	qos_save();
+
+	pd_usb2phy_save();
+
+	if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0)
+		pd_php_save();
+}
+
+static void pmu_power_domains_resume(void)
+{
+	int i;
+
+	for (i = 0; i < pmu_pd_id_max; i++) {
+		/* vop smart/clst pd is not controlled by pmu */
+		if (i == pmu_pd_vop_smart || i == pmu_pd_vop_clst)
+			continue;
+
+		pmu_set_power_domain(i, !!(ddr_data.pmu_pd_st & BIT(i)));
+	}
+
+	/* restore vop smart/clst pd of pmu2_pwrgt_sft_con0 */
+	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0),
+		      0x30000000 | ddr_data.pmu2_pwrgt_sft_con0);
+
+	for (i = pmu_bus_id_max - 1; i >= 0; i--)
+		pmu_bus_idle_req(i, !!(ddr_data.bus_idle_st & BIT(i)));
+
+	if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0)
+		pd_php_restore();
+
+	pd_usb2phy_restore();
+
+	qos_restore();
+}
+
+static void ddr_sleep_config(void)
+{
+	ddr_data.ddrgrf_cha_con2 =
+		mmio_read_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2));
+	ddr_data.ddrgrf_chb_con2 =
+		mmio_read_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2));
+
+	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 0x0a000a00);
+	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 0x0a000a00);
+}
+
+static void ddr_sleep_config_restore(void)
+{
+	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2),
+		      WITH_16BITS_WMSK(ddr_data.ddrgrf_cha_con2));
+	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2),
+		      WITH_16BITS_WMSK(ddr_data.ddrgrf_chb_con2));
+}
+
+static void sleep_pin_config(void)
+{
+	/* pwr0 sleep: gpio0_a3 */
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1),
+		      BITS_WITH_WMASK(0x7, 0xf, 0));
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0),
+		      BITS_WITH_WMASK(0, 0x1, 7));
+	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
+		      BITS_WITH_WMASK(9, 0xfu, 12));
+}
+
+static void pmu_sleep_config(void)
+{
+	uint32_t pmu1_wkup_int_con;
+	uint32_t pmu1_pwr_con, pmu1_ddr_pwr_con, pmu1cru_pwr_con, pmu1_pll_pd_con;
+	uint32_t pmu2_bus_idle_con[2], pmu2_pwr_gt_con[2];
+	uint32_t key_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_vop) ? 0x3 : 0x7;
+	uint32_t fw_lkp_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_npu) ? 0x3 : 0x7;
+	uint32_t fw_ddr_upd_msk = key_upd_msk;
+	uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
+	uint32_t bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST);
+
+	ddr_data.pmu2_bisr_glb_con = mmio_read_32(PMU_BASE + PMU2_BISR_GLB_CON);
+
+	ddr_data.pmu2_fast_pwr_con =
+		mmio_read_32(PMU_BASE + PMU2_FAST_POWER_CON);
+
+	ddr_data.pmu2_c0_ack_sel_con0 =
+		mmio_read_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0));
+	ddr_data.pmu2_c1_ack_sel_con0 =
+		mmio_read_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0));
+	ddr_data.pmu2_c2_ack_sel_con0 =
+		mmio_read_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0));
+	ddr_data.pmu0grf_soc_con5 =
+		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5));
+
+	/* set tsadc_shut_m0 pin iomux to gpio */
+	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
+		      BITS_WITH_WMASK(0, 0xf, 4));
+
+	pmu1_wkup_int_con =
+		BIT(pmu_wkup_cpu0_int) |
+		BIT(pmu_wkup_gpio0_int);
+
+	pmu1_pwr_con =
+		BIT(pmu_powermode_en) |
+		/* BIT(pmu_scu0_byp) | */
+		/* BIT(pmu_scu1_byp) | */
+		/* BIT(pmu_cci_byp) | */
+		/* BIT(pmu_bus_byp) | */
+		/* BIT(pmu_ddr_byp) | */
+		/* BIT(pmu_pwrgt_byp) | */
+		/* BIT(pmu_cru_byp) | */
+		BIT(pmu_qch_byp) |
+		/* BIT(pmu_wfi_byp) | */
+		BIT(pmu_slp_cnt_en);
+
+	pmu1_ddr_pwr_con = 0;
+
+	pmu1_pll_pd_con =
+		BIT(pmu_bpll_pd_en) |
+		BIT(pmu_lpll_pd_en) |
+		BIT(pmu_spll_pd_en) |
+		BIT(pmu_gpll_pd_en) |
+		BIT(pmu_cpll_pd_en) |
+		BIT(pmu_ppll_pd_en) |
+		BIT(pmu_aupll_pd_en) |
+		BIT(pmu_vpll_pd_en);
+
+	pmu1cru_pwr_con =
+		BIT(pmu_alive_osc_mode_en) |
+		BIT(pmu_io_sleep_en) |
+		BIT(pmu_power_off_en);
+
+	pmu2_bus_idle_con[0] = 0xffff & ~(bus_idle_st & 0xffff);
+	pmu2_bus_idle_con[1] = 0x3fff & ~(bus_idle_st >> 16);
+
+	pmu2_pwr_gt_con[0] = 0xffff & ~(pmu_pd_st & 0xffff);
+	pmu2_pwr_gt_con[1] = 0x03ff & ~(pmu_pd_st >> 16);
+
+	pmu2_pwr_gt_con[0] &=
+		~(BIT(pmu_pd_secure) |
+		  BIT(pmu_pd_bus) |
+		  BIT(pmu_pd_center) |
+		  BIT(pmu_pd_ddr));
+
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0x00030003);
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0, 0x03ff0000);
+
+	/* disable repair */
+	mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 0x00010000);
+
+	/* disable ddr_hash_key update.
+	 * enable disable ddr_hash_key auto update.
+	 * wait ddr_hash_key auto update.
+	 */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19),
+		      BITS_WITH_WMASK(key_upd_msk, 0x7, 8));
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1,
+		      BITS_WITH_WMASK(fw_lkp_upd_msk, 0x7, 10));
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1,
+		      BITS_WITH_WMASK(fw_ddr_upd_msk, 0x7u, 13));
+
+	mmio_write_32(PMU_BASE + PMU0_PMIC_STABLE_CNT_THRES, 24000 * 5);
+	mmio_write_32(PMU_BASE + PMU0_OSC_STABLE_CNT_THRES, 24000 * 5);
+
+	mmio_write_32(PMU_BASE + PMU1_OSC_STABLE_CNT_THRESH, 24000 * 5);
+	mmio_write_32(PMU_BASE + PMU1_STABLE_CNT_THRESH, 24000 * 5);
+
+	mmio_write_32(PMU_BASE + PMU1_SLEEP_CNT_THRESH, 24000 * 15);
+
+	/* Pmu's clk has switched to 24M back When pmu FSM counts
+	 * the follow counters, so we should use 24M to calculate
+	 * these counters.
+	 */
+	mmio_write_32(PMU_BASE + PMU0_WAKEUP_RST_CLR_CNT_THRES, 12000);
+
+	mmio_write_32(PMU_BASE + PMU1_WAKEUP_RST_CLR_CNT_THRESH, 12000);
+	mmio_write_32(PMU_BASE + PMU1_PLL_LOCK_CNT_THRESH, 12000);
+	mmio_write_32(PMU_BASE + PMU1_PWM_SWITCH_CNT_THRESH,
+		      24000 * 2);
+
+	mmio_write_32(PMU_BASE + PMU2_SCU0_PWRUP_CNT_THRESH, 0);
+	mmio_write_32(PMU_BASE + PMU2_SCU0_PWRDN_CNT_THRESH, 0);
+	mmio_write_32(PMU_BASE + PMU2_SCU0_STABLE_CNT_THRESH, 0);
+
+	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_0, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_0, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_1, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_1, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_2, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_2, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 0xffff0007);
+
+	/* pmu_clst_idle_con */
+	mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0007);
+	mmio_write_32(PMU_BASE + PMU2_CLUSTER1_IDLE_CON, 0xffff0007);
+
+	/* pmu_scu_pwr_con */
+	/* L2's flush and idle by hardware, so need to enable wfil2 bypass */
+	mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff020f);
+	mmio_write_32(PMU_BASE + PMU2_SCU1_PWR_CON, 0xffff020f);
+	mmio_write_32(PMU_BASE + PMU2_SCU0_AUTO_PWR_CON, 0x00070000);
+	mmio_write_32(PMU_BASE + PMU2_SCU1_AUTO_PWR_CON, 0x00070000);
+
+	mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0009);
+
+	/* pmu_int_msk_con */
+	/* mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, BITS_WITH_WMASK(1, 0x1, 0)); */
+
+	/* pmu_pwr_con */
+	mmio_write_32(PMU_BASE + PMU1_PWR_CON, WITH_16BITS_WMSK(pmu1_pwr_con));
+
+	/* pmu_cru_pwr_conx */
+	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), WITH_16BITS_WMSK(pmu1cru_pwr_con));
+
+	/* pmu_ddr_pwr_con */
+	mmio_write_32(PMU_BASE + PMU0_DDR_RET_CON(1), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
+	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
+	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0x03ff03ff);
+	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0x03ff03ff);
+
+	/* pll_pd */
+	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), WITH_16BITS_WMSK(pmu1_pll_pd_con));
+
+	/* bus idle */
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), WITH_16BITS_WMSK(pmu2_bus_idle_con[0]));
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), WITH_16BITS_WMSK(pmu2_bus_idle_con[1]));
+
+	/* power gate */
+	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), WITH_16BITS_WMSK(pmu2_pwr_gt_con[0]));
+	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), WITH_16BITS_WMSK(pmu2_pwr_gt_con[1]));
+
+	/* vol gate */
+	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0031);
+	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0200);
+
+	/* wakeup source */
+	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, pmu1_wkup_int_con);
+
+	/* ppll clamp */
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 0x00400040);
+
+	/* usbphy clamp */
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5),
+		      BITS_WITH_WMASK(0x9, 0x9, 2));
+
+	/* big core pwr ack bypass */
+	mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 0x01000100);
+	mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 0x01000100);
+	mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 0x01000100);
+}
+
+static void pmu_sleep_restore(void)
+{
+	mmio_write_32(PMU_BASE + PMU0_INFO_TX_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_DEBUG_INFO_SEL, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_PWR_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0xffff0000);
+	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, 0);
+	mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON,
+		      WITH_16BITS_WMSK(ddr_data.pmu2_fast_pwr_con));
+	mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON,
+		      WITH_16BITS_WMSK(ddr_data.pmu2_bisr_glb_con));
+
+	mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0),
+		      WITH_16BITS_WMSK(ddr_data.pmu2_c0_ack_sel_con0));
+	mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0),
+		      WITH_16BITS_WMSK(ddr_data.pmu2_c1_ack_sel_con0));
+	mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0),
+		      WITH_16BITS_WMSK(ddr_data.pmu2_c2_ack_sel_con0));
+
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5),
+		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con5));
+}
+
+static void secure_watchdog_disable(void)
+{
+	ddr_data.sys_sgrf_soc_con0 =
+		mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0));
+
+	/* pause wdt_s */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0),
+		      BITS_WITH_WMASK(1, 0x1, 14));
+}
+
+static void secure_watchdog_restore(void)
+{
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0),
+		      ddr_data.sys_sgrf_soc_con0 |
+		      BITS_WMSK(0x1, 14));
+
+	if (mmio_read_32(WDT_S_BASE + WDT_CR) & WDT_EN)
+		mmio_write_32(WDT_S_BASE + WDT_CRR, 0x76);
+}
+
+static void soc_sleep_config(void)
+{
+	ddr_data.pmu0grf_soc_con0 =
+		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0));
+	ddr_data.pmu0grf_soc_con1 =
+		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1));
+
+	ddr_data.gpio0a_iomux_l =
+		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L);
+	ddr_data.gpio0a_iomux_h =
+		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H);
+	ddr_data.gpio0b_iomux_l =
+		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L);
+
+	sleep_pin_config();
+	pmu_sleep_config();
+	ddr_sleep_config();
+	secure_watchdog_disable();
+}
+
+static void soc_sleep_restore(void)
+{
+	secure_watchdog_restore();
+	ddr_sleep_config_restore();
+	pmu_sleep_restore();
+
+	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
+		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l));
+	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H,
+		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h));
+	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L,
+		      WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l));
+
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1),
+		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con1));
+	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0),
+		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con0));
+}
+
+static void pm_pll_suspend(void)
+{
+	ddr_data.cru_mode_con = mmio_read_32(CRU_BASE + 0x280);
+	ddr_data.secure_cru_mode = mmio_read_32(SECURE_CRU_BASE + 0x4280);
+
+	/* bpll gpll vpll aupll cpll spll switch to slow mode */
+	mmio_write_32(CRU_BASE + 0x280, 0x03ff0000);
+	mmio_write_32(SECURE_CRU_BASE + 0x4280, 0x00030000);
+
+	/* hclk_pmu_cm0_root_i_sel to 24M */
+	mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKSEL_CON(4),
+		      BITS_WITH_WMASK(0x3, 0x3, 2));
+}
+
+static void pm_pll_restore(void)
+{
+	mmio_write_32(CRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.cru_mode_con));
+	mmio_write_32(SECURE_CRU_BASE + 0x4280,
+		      WITH_16BITS_WMSK(ddr_data.secure_cru_mode));
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	psram_sleep_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
+
+	clk_gate_con_save();
+	clk_gate_con_disable();
+	dmc_save();
+	pmu_power_domains_suspend();
+	soc_sleep_config();
+	pm_pll_suspend();
+	pd_core_save();
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	pd_core_restore();
+	pm_pll_restore();
+	soc_sleep_restore();
+	pmu_power_domains_resume();
+	plat_rockchip_gic_cpuif_enable();
+	dmc_restore();
+	clk_gate_con_restore();
+
+	psram_sleep_cfg->pm_flag |= PM_WARM_BOOT_BIT;
+
+	return 0;
+}
+
+void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(const
+					      psci_power_state_t *target_state)
+{
+	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
+}
+
+void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
+{
+	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
+}
+
+static int rockchip_reboot_is_rbrom(void)
+{
+	return mmio_read_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(16)) ==
+	       BOOT_BROM_DOWNLOAD;
+}
+
+static void rockchip_soc_soft_reset_check_rstout(void)
+{
+	/*
+	 * Maskrom enter maskrom-usb mode according to os_reg0 which
+	 * will be reset by NPOR. So disable tsadc_shut_m0 if we want
+	 * to maskrom-usb mode.
+	 */
+	if (rockchip_reboot_is_rbrom() != 0) {
+		/* write BOOT_BROM_DOWNLOAD to os_reg0 */
+		mmio_write_32(PMU1_GRF_BASE + PMU1GRF_OS_REG(0), BOOT_BROM_DOWNLOAD);
+
+		/* disable first/tsadc/wdt reset output */
+		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070000);
+
+		/* clear reset hold */
+		mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(1), 0xffff0000);
+		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(16), 0xffff0000);
+		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(17), 0xffff0000);
+	}
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	rockchip_soc_soft_reset_check_rstout();
+
+	/* pll slow mode */
+	mmio_write_32(CRU_BASE + CRU_MODE_CON, 0x003f0000);
+
+	dsb();
+	isb();
+
+	INFO("system reset......\n");
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to execute valid codes.
+	 */
+	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
+}
+
+void __dead2 rockchip_soc_system_off(void)
+{
+	INFO("system poweroff......\n");
+
+	/* gpio0_a3 config output */
+	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DDR_L,
+		      BITS_WITH_WMASK(1, 0x1, 3));
+
+	/* gpio0_a3 config output high level */
+	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DR_L,
+		      BITS_WITH_WMASK(1, 0x1, 3));
+	dsb();
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to execute valid codes.
+	 */
+	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
+}
+
+static void rockchip_pmu_pd_repair_init(void)
+{
+	INFO("enable memory repair\n");
+	/* Enable gpu and npu repair */
+	mmio_write_32(PMU_BASE + PMU2_BISR_PDGEN_CON(1),
+		      BITS_WITH_WMASK(0xf, 0xf, 6));
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	int cpu;
+
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = 0;
+
+	psram_sleep_cfg->sp = PSRAM_SP_TOP;
+	psram_sleep_cfg->ddr_func = (uint64_t)ddr_resume;
+	psram_sleep_cfg->ddr_data = 0;
+	psram_sleep_cfg->ddr_flag = 0;
+	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
+	psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT;
+
+	nonboot_cpus_off();
+
+	/*
+	 * When perform idle operation, corresponding clock can be
+	 * opened or gated automatically.
+	 */
+	mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(0), 0xffffffff);
+	mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(1), 0xffffffff);
+
+	/* remap pmusram to 0x00000000 */
+	mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(2), BITS_WITH_WMASK(1, 0x3, 0));
+
+	/* enable power off VD_NPU by hrdware */
+	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0),
+		      BITS_WITH_WMASK(0x1, 0x1, 0));
+
+	rockchip_pmu_pd_repair_init();
+
+	pm_reg_rgns_init();
+}
diff --git a/plat/rockchip/rk3576/drivers/pmu/pmu.h b/plat/rockchip/rk3576/drivers/pmu/pmu.h
new file mode 100644
index 0000000..6340e3f
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/pmu/pmu.h
@@ -0,0 +1,578 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __PMU_H__
+#define __PMU_H__
+
+#include <assert.h>
+
+#include <mmio.h>
+
+/* PMU */
+#define PMU1_OFFSET			0x10000
+#define PMU2_OFFSET			0x20000
+
+#define PMU0_PWR_CON			0x0000
+#define PMU0_PWR_STATUS			0x0004
+#define PMU0_WAKEUP_INT_CON		0x0008
+#define PMU0_WAKEUP_INT_ST		0x000c
+#define PMU0_PMIC_STABLE_CNT_THRES	0x0010
+#define PMU0_WAKEUP_RST_CLR_CNT_THRES	0x0014
+#define PMU0_OSC_STABLE_CNT_THRES	0x0018
+#define PMU0_PWR_C0_STABLE_CON		0x001c
+#define PMU0_DDR_RET_CON(i)		(0x0020 + (i) * 4)
+#define PMU0_INFO_TX_CON		0x0030
+
+#define PMU1_VERSION_ID			(PMU1_OFFSET + 0x0000)
+#define PMU1_PWR_CON			(PMU1_OFFSET + 0x0004)
+#define PMU1_PWR_FSM			(PMU1_OFFSET + 0x0008)
+#define PMU1_INT_MASK_CON		(PMU1_OFFSET + 0x000c)
+#define PMU1_WAKEUP_INT_CON		(PMU1_OFFSET + 0x0010)
+#define PMU1_WAKEUP_INT_ST		(PMU1_OFFSET + 0x0014)
+#define PMU1_DDR_PWR_CON(i)		(PMU1_OFFSET + 0x0100 + (i) * 4)
+#define PMU1_DDR_PWR_SFTCON(i)		(PMU1_OFFSET + 0x0110 + (i) * 4)
+#define PMU1_DDR_AXIPWR_CON(i)		(PMU1_OFFSET + 0x0120 + (i) * 4)
+#define PMU1_DDR_AXIPWR_SFTCON(i)	(PMU1_OFFSET + 0x0130 + (i) * 4)
+#define PMU1_DDR_PWR_FSM		(PMU1_OFFSET + 0x0140)
+#define PMU1_DDR_PWR_ST			(PMU1_OFFSET + 0x0144)
+#define PMU1_DDR_AXIPWR_ST		(PMU1_OFFSET + 0x0148)
+#define PMU1_CRU_PWR_CON(i)		(PMU1_OFFSET + 0x0200 + (i) * 4)
+#define PMU1_CRU_PWR_SFTCON(i)		(PMU1_OFFSET + 0x0208 + (i) * 4)
+#define PMU1_CRU_PWR_FSM		(PMU1_OFFSET + 0x0210)
+#define PMU1_PLLPD_CON(i)		(PMU1_OFFSET + 0x0220 + (i) * 4)
+#define PMU1_PLLPD_SFTCON(i)		(PMU1_OFFSET + 0x0228 + (i) * 4)
+#define PMU1_STABLE_CNT_THRESH		(PMU1_OFFSET + 0x0300)
+#define PMU1_OSC_STABLE_CNT_THRESH	(PMU1_OFFSET + 0x0304)
+#define PMU1_WAKEUP_RST_CLR_CNT_THRESH	(PMU1_OFFSET + 0x0308)
+#define PMU1_PLL_LOCK_CNT_THRESH	(PMU1_OFFSET + 0x030c)
+#define PMU1_WAKEUP_TIMEOUT_THRESH	(PMU1_OFFSET + 0x0310)
+#define PMU1_PWM_SWITCH_CNT_THRESH	(PMU1_OFFSET + 0x0314)
+#define PMU1_SLEEP_CNT_THRESH		(PMU1_OFFSET + 0x0318)
+#define PMU1_INFO_TX_CON		(PMU1_OFFSET + 0x0400)
+
+#define PMU2_SCU0_PWR_CON		(PMU2_OFFSET + 0x0000)
+#define PMU2_SCU1_PWR_CON		(PMU2_OFFSET + 0x0004)
+#define PMU2_SCU0_PWR_SFTCON		(PMU2_OFFSET + 0x0008)
+#define PMU2_SCU1_PWR_SFTCON		(PMU2_OFFSET + 0x000c)
+#define PMU2_SCU0_AUTO_PWR_CON		(PMU2_OFFSET + 0x0010)
+#define PMU2_SCU1_AUTO_PWR_CON		(PMU2_OFFSET + 0x0014)
+#define PMU2_SCU_PWR_FSM_STATUS		(PMU2_OFFSET + 0x0018)
+#define PMU2_DBG_PWR_CON(i)		(PMU2_OFFSET + 0x001c + (i) * 4)
+#define PMU2_CLUSTER_PWR_ST		(PMU2_OFFSET + 0x0024)
+#define PMU2_CLUSTER0_IDLE_CON		(PMU2_OFFSET + 0x0028)
+#define PMU2_CLUSTER1_IDLE_CON		(PMU2_OFFSET + 0x002c)
+#define PMU2_CLUSTER0_IDLE_SFTCON	(PMU2_OFFSET + 0x0030)
+#define PMU2_CLUSTER1_IDLE_SFTCON	(PMU2_OFFSET + 0x0034)
+#define PMU2_CLUSTER_IDLE_ACK		(PMU2_OFFSET + 0x0038)
+#define PMU2_CLUSTER_IDLE_ST		(PMU2_OFFSET + 0x003c)
+#define PMU2_SCU0_PWRUP_CNT_THRESH	(PMU2_OFFSET + 0x0040)
+#define PMU2_SCU0_PWRDN_CNT_THRESH	(PMU2_OFFSET + 0x0044)
+#define PMU2_SCU0_STABLE_CNT_THRESH	(PMU2_OFFSET + 0x0048)
+#define PMU2_SCU1_PWRUP_CNT_THRESH	(PMU2_OFFSET + 0x004c)
+#define PMU2_SCU1_PWRDN_CNT_THRESH	(PMU2_OFFSET + 0x0050)
+#define PMU2_SCU1_STABLE_CNT_THRESH	(PMU2_OFFSET + 0x0054)
+#define PMU2_CPU_AUTO_PWR_CON(i)	(PMU2_OFFSET + 0x0080 + ((i)) * 4)
+#define PMU2_CPU_PWR_SFTCON(i)		(PMU2_OFFSET + 0x00a0 + ((i)) * 4)
+#define PMU2_CCI_PWR_CON		(PMU2_OFFSET + 0x00e0)
+#define PMU2_CCI_PWR_SFTCON		(PMU2_OFFSET + 0x00e4)
+#define PMU2_CCI_PWR_ST			(PMU2_OFFSET + 0x00e8)
+#define PMU2_CCI_POWER_STATE		(PMU2_OFFSET + 0x00ec)
+#define PMU2_BUS_IDLE_CON(i)		(PMU2_OFFSET + 0x0100 + (i) * 4)
+#define PMU2_BUS_IDLE_SFTCON(i)		(PMU2_OFFSET + 0x0110 + (i) * 4)
+#define PMU2_BUS_IDLE_ACK		(PMU2_OFFSET + 0x0120)
+#define PMU2_BUS_IDLE_ST		(PMU2_OFFSET + 0x0128)
+#define PMU2_NOC_AUTO_CON(i)		(PMU2_OFFSET + 0x0130 + (i) * 4)
+#define PMU2_NOC_AUTO_SFTCON(i)		(PMU2_OFFSET + 0x0140 + (i) * 4)
+#define PMU2_BUS_IDLEACK_BYPASS_CON	(PMU2_OFFSET + 0x0150)
+#define PMU2_PWR_GATE_CON(i)		(PMU2_OFFSET + 0x0200 + (i) * 4)
+#define PMU2_PWR_GATE_SFTCON(i)		(PMU2_OFFSET + 0x0210 + (i) * 4)
+#define PMU2_VOL_GATE_SFTCON(i)		(PMU2_OFFSET + 0x0220 + (i) * 4)
+#define PMU2_PWR_GATE_ST		(PMU2_OFFSET + 0x0230)
+#define PMU2_PWR_GATE_FSM		(PMU2_OFFSET + 0x0238)
+#define PMU2_PD_DWN_ACK_STATE(i)	(PMU2_OFFSET + 0x0240 + (i) * 4)
+#define PMU2_PD_DWN_LC_ACK_STATE(i)	(PMU2_OFFSET + 0x0248 + (i) * 4)
+#define PMU2_PD_DWN_MEM_ACK_STATE(i)	(PMU2_OFFSET + 0x0250 + (i) * 4)
+#define PMU2_PWR_UP_C0_STABLE_CON(i)	(PMU2_OFFSET + 0x0260 + (i) * 4)
+#define PMU2_PWR_DWN_C0_STABLE_CON(i)	(PMU2_OFFSET + 0x0270 + (i) * 4)
+#define PMU2_PWR_STABLE_C0_CNT_THRES	(PMU2_OFFSET + 0x027c)
+#define PMU2_FAST_POWER_CON		(PMU2_OFFSET + 0x0284)
+#define PMU2_FAST_PWRUP_CNT_THRESH_0	(PMU2_OFFSET + 0x0288)
+#define PMU2_FAST_PWRDN_CNT_THRESH_0	(PMU2_OFFSET + 0x028c)
+#define PMU2_FAST_PWRUP_CNT_THRESH_1	(PMU2_OFFSET + 0x0290)
+#define PMU2_FAST_PWRDN_CNT_THRESH_1	(PMU2_OFFSET + 0x0294)
+#define PMU2_FAST_PWRUP_CNT_THRESH_2	(PMU2_OFFSET + 0x0298)
+#define PMU2_FAST_PWRDN_CNT_THRESH_2	(PMU2_OFFSET + 0x029c)
+#define PMU2_MEM_PWR_GATE_SFTCON(i)	(PMU2_OFFSET + 0x0300)
+#define PMU2_SUBMEM_PWR_GATE_SFTCON(i)	(PMU2_OFFSET + 0x0310)
+#define PMU2_SUBMEM_PWR_ACK_BYPASS_SFTCON(i)	(PMU2_OFFSET + 0x0320)
+#define PMU2_SUBMEM_PWR_GATE_STATUS	(PMU2_OFFSET + 0x0328)
+#define PMU2_QCHANNEL_PWR_CON0		(PMU2_OFFSET + 0x0400)
+#define PMU2_QCHANNEL_PWR_SFTCON0	(PMU2_OFFSET + 0x0404)
+#define PMU2_QCHANNEL_STATUS0		(PMU2_OFFSET + 0x0408)
+#define PMU2_C0_PWRACK_BYPASS_CON(i)	(PMU2_OFFSET + 0x0380 + (i) * 4)
+#define PMU2_C1_PWRACK_BYPASS_CON(i)	(PMU2_OFFSET + 0x0390 + (i) * 4)
+#define PMU2_C2_PWRACK_BYPASS_CON(i)	(PMU2_OFFSET + 0x03a0 + (i) * 4)
+#define PMU2_DEBUG_INFO_SEL		(PMU2_OFFSET + 0x03f0)
+#define PMU2_BISR_GLB_CON		(PMU2_OFFSET + 0x500)
+#define PMU2_BISR_TIMEOUT_THRES		(PMU2_OFFSET + 0x504)
+#define PMU2_BISR_PDGEN_CON(i)		(PMU2_OFFSET + 0x510 + (i) * 4)
+#define PMU2_BISR_PDGEN_SFTCON(i)	(PMU2_OFFSET + 0x520 + (i) * 4)
+#define PMU2_BISR_PDGDONE_CON(i)	(PMU2_OFFSET + 0x530 + (i) * 4)
+#define PMU2_BISR_PDGINIT_CON(i)	(PMU2_OFFSET + 0x540 + (i) * 4)
+#define PMU2_BISR_PDGDONE_STATUS(i)	(PMU2_OFFSET + 0x550 + (i) * 4)
+#define PMU2_BISR_PDGCEDIS_STATUS(i)	(PMU2_OFFSET + 0x560 + (i) * 4)
+#define PMU2_BISR_PWR_REPAIR_STATUS(i)	(PMU2_OFFSET + 0x570 + (i) * 4)
+
+/* PMU1CRU */
+#define PMU1CRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define PMU1CRU_CLKSEL_CON_CNT		22
+#define PMU1CRU_CLKGATE_CON(i)		((i) * 0x4 + 0x800)
+#define PMU1CRU_CLKGATE_CON_CNT		8
+#define PMU1CRU_SOFTRST_CON(i)		((i) * 0x4 + 0xa00)
+#define PMU1CRU_SOFTRST_CON_CNT		8
+#define PMU1CRU_DEEPSLOW_DET_CON	0xb40
+#define PMU1CRU_DEEPSLOW_DET_ST		0xb44
+
+/* PMU1SCRU */
+#define PMU1SCRU_CLKSEL_CON(i)		((i) * 0x4 + 0x4000)
+#define PMU1SCRU_CLKSEL_CON_CNT		3
+#define PMU1SCRU_CLKGATE_CON(i)		((i) * 0x4 + 0x4028)
+#define PMU1SCRU_CLKGATE_CON_CNT		3
+#define PMU1SCRU_SOFTRST_CON(i)		((i) * 0x4 + 0x4050)
+#define PMU1SCRU_SOFTRST_CONCNT		3
+
+/* PMU0GRF */
+#define PMU0GRF_SOC_CON(i)		((i) * 4)
+#define PMU0GRF_IO_RET_CON(i)		(0x20 + (i) * 4)
+#define PMU0GRF_OS_REG(i)		((i) * 4)
+
+/* PMU1GRF */
+#define PMU1GRF_SOC_CON(i)		((i) * 4)
+#define PMU1GRF_SOC_ST			0x60
+#define PMU1GRF_MEM_CON(i)		(0x80 + (i) * 4)
+#define PMU1GRF_OS_REG(i)		(0x200 + (i) * 4)
+
+#define PMU_MCU_HALT			BIT(7)
+#define PMU_MCU_SLEEP			BIT(9)
+#define PMU_MCU_DEEPSLEEP		BIT(10)
+#define PMU_MCU_STOP_MSK		\
+	(PMU_MCU_HALT | PMU_MCU_SLEEP | PMU_MCU_DEEPSLEEP)
+
+#define CORES_PM_DISABLE		0x0
+
+/* pmuioc */
+#define PMUIO0_IOC_GPIO0A_IOMUX_SEL_L	0x000
+#define PMUIO0_IOC_GPIO0A_IOMUX_SEL_H	0x004
+#define PMUIO0_IOC_GPIO0B_IOMUX_SEL_L	0x008
+
+#define PMUIO1_IOC_GPIO0B_IOMUX_SEL_H	0x000
+#define PMUIO1_IOC_GPIO0C_IOMUX_SEL_L	0x004
+#define PMUIO1_IOC_GPIO0C_IOMUX_SEL_H	0x008
+#define PMUIO1_IOC_GPIO0D_IOMUX_SEL_L	0x00c
+#define PMUIO1_IOC_GPIO0D_IOMUX_SEL_H	0x010
+
+/* PMU_PWR_CON */
+enum pmu0_pwr_con {
+	pmu_powermode0_en = 0,
+	pmu_pmu1_pd_byp = 1,
+	pmu_pmu1_bus_byp = 2,
+	pmu_pmu0_wkup_byp = 3,
+	pmu_pmu0_pmic_byp = 4,
+	pmu_pmu0_reset_byp = 5,
+	pmu_pmu0_freq_switch_byp = 6,
+	pmu_pmu0_osc_dis_byp = 7,
+	pmu_pmu1_pwrgt = 8,
+	pmu_pmu1_pwrgt_sft = 9,
+	pmu_pmu1_mempwr_sft_gt = 10,
+	pmu_pmu1_idle_en = 11,
+	pmu_pmu1_idle_sft_en = 12,
+	pmu_pmu1_noc_auto_en = 13,
+	pmu_pmu1_off_io_en = 14,
+};
+
+enum pmu1_pwr_con {
+	pmu_powermode_en = 0,
+	pmu_scu0_byp = 1,
+	pmu_scu1_byp = 2,
+	pmu_cci_byp = 3,
+	pmu_bus_byp = 4,
+	pmu_ddr_byp = 5,
+	pmu_pwrgt_byp = 6,
+	pmu_cru_byp = 7,
+	pmu_qch_byp = 8,
+	pmu_wfi_byp = 12,
+	pmu_slp_cnt_en = 13,
+};
+
+enum pmu_wakeup_int {
+	pmu_wkup_cpu0_int = 0,
+	pmu_wkup_cpu1_int = 1,
+	pmu_wkup_cpu2_int = 2,
+	pmu_wkup_cpu3_int = 3,
+	pmu_wkup_cpu4_int = 4,
+	pmu_wkup_cpu5_int = 5,
+	pmu_wkup_cpu6_int = 6,
+	pmu_wkup_cpu7_int = 7,
+	pmu_wkup_gpio0_int = 8,
+	pmu_wkup_sdmmc_int = 9,
+	pmu_wkup_sdio_int = 10,
+	pmu_wkup_usbdev_int = 11,
+	pmu_wkup_uart_int = 12,
+	pmu_wkup_mcu_int = 13,
+	pmu_wkup_timer_int = 14,
+	pmu_wkup_sys_int = 15,
+	pmu_wkup_pwm_int = 16,
+	pmu_wkup_tsadc_int = 17,
+	pmu_wkup_hptimer_int = 18,
+	pmu_wkup_saradc_int = 19,
+	pmu_wkup_timeout = 20,
+};
+
+/* PMU_DDR_PWR_CON */
+enum pmu_ddr_pwr_con {
+	pmu_ddr_sref_c_en = 0,
+	pmu_ddr_ioret_en = 1,
+	pmu_ddr_ioret_exit_en = 2,
+	pmu_ddr_rstiov_en = 3,
+	pmu_ddr_rstiov_exit_en = 4,
+	pmu_ddr_gating_c_en = 5,
+	pmu_ddr_gating_p_en = 6,
+};
+
+/* PMU_CRU_PWR_CON0 */
+enum pmu_cru_pwr_con0 {
+	pmu_alive_32k_en = 0,
+	pmu_osc_dis_en = 1,
+	pmu_wakeup_rst_en = 2,
+	pmu_input_clamp_en = 3,
+	pmu_alive_osc_mode_en = 4,
+	pmu_power_off_en = 5,
+	pmu_pwm_switch_en = 6,
+	pmu_pwm_gpio_ioe_en = 7,
+	pmu_pwm_switch_io = 8,
+	pmu_io_sleep_en = 9,
+};
+
+/* PMU_CRU_PWR_CON1 */
+enum pmu_cru_pwr_con1 {
+	pmu_bus_clksrc_gt_en = 0,
+	pmu_vpu_clksrc_gt_en = 1,
+	pmu_vo_clksrc_gt_en = 2,
+	pmu_gpu_clksrc_gt_en = 3,
+	pmu_rkenc_clksrc_gt_en = 4,
+	pmu_rkvdec_clksrc_gt_en = 5,
+	pmu_core_clksrc_gt_en = 6,
+	pmu_ddr_clksrc_gt_en = 7,
+};
+
+/* PMU_SCU_PWR_CON */
+enum pmu_scu_pwr_con {
+	pmu_l2_flush_en = 0,
+	pmu_l2_ilde_en = 1,
+	pmu_scu_pd_en = 2,
+	pmu_scu_pwroff_en = 3,
+	pmu_clst_cpu_pd_en = 5,
+	pmu_std_wfi_bypass = 8,
+	pmu_std_wfil2_bypass = 9,
+	pmu_scu_vol_gt_en = 10,
+};
+
+/* PMU_PLLPD_CON */
+enum pmu_pllpd_con {
+	pmu_d0apll_pd_en = 0,
+	pmu_d0bpll_pd_en = 1,
+	pmu_d1apll_pd_en = 2,
+	pmu_d1bpll_pd_en = 3,
+	pmu_bpll_pd_en = 4,
+	pmu_lpll_pd_en = 5,
+	pmu_spll_pd_en = 6,
+	pmu_gpll_pd_en = 7,
+	pmu_cpll_pd_en = 8,
+	pmu_ppll_pd_en = 9,
+	pmu_aupll_pd_en = 10,
+	pmu_vpll_pd_en = 11,
+};
+
+/* PMU_CLST_PWR_ST */
+enum pmu_clst_pwr_st {
+	pmu_cpu0_wfi = 0,
+	pmu_cpu1_wfi = 1,
+	pmu_cpu2_wfi = 2,
+	pmu_cpu3_wfi = 3,
+	pmu_cpu4_wfi = 4,
+	pmu_cpu5_wfi = 5,
+	pmu_cpu6_wfi = 6,
+	pmu_cpu7_wfi = 7,
+	pmu_scu0_standbywfil2 = 8,
+	pmu_scu1_standbywfil2 = 9,
+	pmu_scu0_l2flushdone = 10,
+	pmu_scu1_l2flushdone = 11,
+	pmu_cpu0_pd_st = 16,
+	pmu_cpu1_pd_st = 17,
+	pmu_cpu2_pd_st = 18,
+	pmu_cpu3_pd_st = 19,
+	pmu_cpu4_pd_st = 20,
+	pmu_cpu5_pd_st = 21,
+	pmu_cpu6_pd_st = 22,
+	pmu_cpu7_pd_st = 23,
+	pmu_scu0_pd_st = 24,
+	pmu_scu1_pd_st = 25,
+};
+
+/* PMU_CLST_IDLE_CON */
+enum pmu_clst_idle_con {
+	pmu_adb400s_idle_req = 0,
+	pmu_clst_biu_idle_req = 1,
+	pmu_clst_clk_gt_msk = 2,
+};
+
+enum cores_pm_ctr_mode {
+	core_pwr_pd = 0,
+	core_pwr_wfi = 1,
+	core_pwr_wfi_int = 2,
+	core_pwr_wfi_reset = 3,
+};
+
+/* PMU_CPUX_AUTO_PWR_CON */
+enum pmu_cpu_auto_pwr_con {
+	pmu_cpu_pm_en = 0,
+	pmu_cpu_pm_int_wakeup_en = 1,
+	pmu_cpu_pm_dis_int = 2,
+	pmu_cpu_pm_sft_wakeup_en = 3,
+};
+
+enum qos_id {
+	qos_decom = 0,
+	qos_dmac0 = 1,
+	qos_dmac1 = 2,
+	qos_dmac2 = 3,
+	qos_bus_mcu = 4,
+	qos_can0 = 5,
+	qos_can1 = 6,
+	qos_cci_m0 = 7,
+	qos_cci_m1 = 8,
+	qos_cci_m2 = 9,
+	qos_dap_lite = 10,
+	qos_hdcp1 = 11,
+	qos_ddr_mcu = 12,
+	qos_fspi1 = 13,
+	qos_gmac0 = 14,
+	qos_gmac1 = 15,
+	qos_sdio = 16,
+	qos_sdmmc = 17,
+	qos_flexbus = 18,
+	qos_gpu = 19,
+	qos_vepu1 = 20,
+	qos_npu_mcu = 21,
+	qos_npu_nsp0 = 22,
+	qos_npu_nsp1 = 23,
+	qos_npu_m0 = 24,
+	qos_npu_m1 = 25,
+	qos_npu_m0ro = 26,
+	qos_npu_m1ro = 27,
+	qos_emmc = 28,
+	qos_fspi0 = 29,
+	qos_mmu0 = 30,
+	qos_mmu1 = 31,
+	qos_pmu_mcu = 32,
+	qos_rkvdec = 33,
+	qos_crypto = 34,
+	qos_mmu2 = 35,
+	qos_ufshc = 36,
+	qos_vepu0 = 37,
+	qos_isp_mro = 38,
+	qos_isp_mwo = 39,
+	qos_vicap_m0 = 40,
+	qos_vpss_mro = 41,
+	qos_vpss_mwo = 42,
+	qos_hdcp0 = 43,
+	qos_vop_m0 = 44,
+	qos_vop_m1ro = 45,
+	qos_ebc = 46,
+	qos_rga0 = 47,
+	qos_rga1 = 48,
+	qos_jpeg = 49,
+	qos_vdpp = 50,
+	qos_dma2ddr = 51,
+};
+
+enum pmu_bus_id {
+	pmu_bus_id_gpu = 0,
+	pmu_bus_id_npu0 = 1,
+	pmu_bus_id_npu1 = 2,
+	pmu_bus_id_nputop = 3,
+	pmu_bus_id_npusys = 4,
+	pmu_bus_id_vpu = 5,
+	pmu_bus_id_vdec = 6,
+	pmu_bus_id_vepu0 = 7,
+	pmu_bus_id_vepu1 = 8,
+	pmu_bus_id_vi = 9,
+	pmu_bus_id_usb = 10,
+	pmu_bus_id_vo0 = 11,
+	pmu_bus_id_vo1 = 12,
+	pmu_bus_id_vop = 13,
+	pmu_bus_id_vop_nocddrsch = 14,
+	pmu_bus_id_php = 15,
+	pmu_bus_id_audio = 16,
+	pmu_bus_id_gmac = 17,
+	pmu_bus_id_nvm = 18,
+	pmu_bus_id_center_nocddrsch = 19,
+	pmu_bus_id_center_nocmain = 20,
+	pmu_bus_id_ddr = 21,
+	pmu_bus_id_ddrsch0 = 22,
+	pmu_bus_id_ddrsch1 = 23,
+	pmu_bus_id_bus = 24,
+	pmu_bus_id_secure = 25,
+	pmu_bus_id_top = 26,
+	pmu_bus_id_vo0vop_chn = 27,
+	pmu_bus_id_cci = 28,
+	pmu_bus_id_cci_nocddrsch = 29,
+	pmu_bus_id_max,
+};
+
+enum pmu_pd_id {
+	pmu_pd_npu = 0,
+	pmu_pd_bus = 1,
+	pmu_pd_secure = 2,
+	pmu_pd_center = 3,
+	pmu_pd_ddr = 4,
+	pmu_pd_cci = 5,
+	pmu_pd_nvm = 6,
+	pmu_pd_sd_gmac = 7,
+	pmu_pd_audio = 8,
+	pmu_pd_php = 9,
+	pmu_pd_subphp = 10,
+	pmu_pd_vop = 11,
+	pmu_pd_vop_smart = 12,
+	pmu_pd_vop_clst = 13,
+	pmu_pd_vo1 = 14,
+	pmu_pd_vo0 = 15,
+	pmu_pd_usb = 16,
+	pmu_pd_vi = 17,
+	pmu_pd_vepu0 = 18,
+	pmu_pd_vepu1 = 19,
+	pmu_pd_vdec = 20,
+	pmu_pd_vpu = 21,
+	pmu_pd_nputop = 22,
+	pmu_pd_npu0 = 23,
+	pmu_pd_npu1 = 24,
+	pmu_pd_gpu = 25,
+	pmu_pd_id_max,
+};
+
+enum pmu_vd_id {
+	pmu_vd_npu = 0,
+	pmu_vd_ddr = 1,
+	pmu_vd_cci = 2,
+	pmu_vd_gpu = 3,
+};
+
+enum pmu_bus_state {
+	pmu_bus_active = 0,
+	pmu_bus_idle = 1,
+};
+
+enum pmu_pd_state {
+	pmu_pd_on = 0,
+	pmu_pd_off = 1
+};
+
+enum pmu_scu_fsm_st {
+	pmu_scu_fsm_normal = 0,
+	pmu_scu_fsm_cpu_pwr_down = 1,
+	pmu_scu_fsm_l2_flush = 2,
+	pmu_scu_fsm_l2_idle = 3,
+	pmu_scu_fsm_clust_idle = 4,
+	pmu_scu_fsm_scu_pwr_down = 5,
+	pmu_scu_fsm_sleep = 6,
+	pmu_scu_fsm_wkup = 7,
+	pmu_scu_fsm_scu_pwr_up = 8,
+	pmu_scu_fsm_clust_resume = 9,
+	pmu_scu_fsm_cpu_pwr_up = 10,
+};
+
+#define MAX_MEM_OS_REG_NUM		32
+#define MEM_OS_REG_BASE			\
+	(PMUSRAM_BASE + PMUSRAM_RSIZE - MAX_MEM_OS_REG_NUM * 4)
+
+#define PSRAM_SP_TOP			MEM_OS_REG_BASE
+
+#define PD_CTR_LOOP			5000
+#define WFEI_CHECK_LOOP			5000
+#define BUS_IDLE_LOOP			1000
+#define NONBOOT_CPUS_OFF_LOOP		500000
+
+#define REBOOT_FLAG			0x5242C300
+#define BOOT_BROM_DOWNLOAD		0xef08a53c
+
+#define BOOTROM_SUSPEND_MAGIC		0x02468ace
+#define BOOTROM_RESUME_MAGIC		0x13579bdf
+#define WARM_BOOT_MAGIC			0x76543210
+#define VALID_GLB_RST_MSK		0xbfff
+
+#define DEFAULT_BOOT_CPU		0
+
+/*******************************************************
+ *     sleep mode define
+ *******************************************************/
+#define SLP_ARMPD			BIT(0)
+#define SLP_ARMOFF			BIT(1)
+#define SLP_ARMOFF_DDRPD		BIT(2)
+#define SLP_ARMOFF_LOGOFF		BIT(3)
+#define SLP_ARMOFF_PMUOFF		BIT(4)
+#define SLP_FROM_UBOOT			BIT(5)
+
+/* all plls except ddr's pll*/
+#define SLP_PMU_HW_PLLS_PD		BIT(8)
+#define SLP_PMU_PMUALIVE_32K		BIT(9)
+#define SLP_PMU_DIS_OSC			BIT(10)
+
+#define SLP_CLK_GT			BIT(16)
+#define SLP_PMIC_LP			BIT(17)
+
+#define SLP_32K_EXT			BIT(24)
+#define SLP_TIME_OUT_WKUP		BIT(25)
+#define SLP_PMU_DBG			BIT(26)
+#define SLP_ARCH_TIMER_RESET		BIT(27)
+
+#define PM_INVALID_GPIO			0xffff
+#define MAX_GPIO_POWER_CFG_CNT		10
+#define MAX_VIRTUAL_PWROFF_IRQ_CNT	20
+
+enum {
+	RK_PM_VIRT_PWROFF_EN = 0,
+	RK_PM_VIRT_PWROFF_IRQ_CFG = 1,
+	RK_PM_VIRT_PWROFF_MAX,
+};
+
+/* sleep pin */
+#define RKPM_SLEEP_PIN0_EN		BIT(0)	/* GPIO0_A3 */
+#define RKPM_SLEEP_PIN1_EN		BIT(1)	/* GPIO0_A4 */
+#define RKPM_SLEEP_PIN2_EN		BIT(2)	/* GPIO0_A5 */
+
+#define RKPM_SLEEP_PIN0_ACT_LOW		BIT(0)	/* GPIO0_A3 */
+#define RKPM_SLEEP_PIN1_ACT_LOW		BIT(1)	/* GPIO0_A4 */
+#define RKPM_SLEEP_PIN2_ACT_LOW		BIT(2)	/* GPIO0_A5 */
+
+#define pmu_bus_idle_st(id)	\
+	(!!(mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST) & BIT(id)))
+
+#define pmu_bus_idle_ack(id)	\
+	(!!(mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ACK) & BIT(id)))
+
+static inline uint32_t read_mem_os_reg(uint32_t id)
+{
+	assert((id) < MAX_MEM_OS_REG_NUM);
+
+	return mmio_read_32(MEM_OS_REG_BASE + 4 * (id));
+}
+
+static inline void write_mem_os_reg(uint32_t id, uint32_t val)
+{
+	assert((id) < MAX_MEM_OS_REG_NUM);
+
+	mmio_write_32(MEM_OS_REG_BASE + 4 * (id), val);
+}
+#endif /* __PMU_H__ */
diff --git a/plat/rockchip/rk3576/drivers/secure/firewall.c b/plat/rockchip/rk3576/drivers/secure/firewall.c
new file mode 100644
index 0000000..5da9ea8
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/secure/firewall.c
@@ -0,0 +1,693 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include <firewall.h>
+#include <soc.h>
+
+enum {
+	FW_NS_A_S_A = 0x0,
+	FW_NS_A_S_NA = 0x1,
+	FW_NS_NA_S_A = 0x2,
+	FW_NS_NA_S_NA = 0x3,
+};
+
+/* group type */
+enum {
+	FW_GRP_TYPE_INV = 0,
+	FW_GRP_TYPE_DDR_RGN = 1,
+	FW_GRP_TYPE_SYSMEM_RGN = 2,
+	FW_GRP_TYPE_CBUF_RGN = 3,
+	FW_GRP_TYPE_SLV = 4,
+	FW_GRP_TYPE_DM = 5,
+};
+
+enum {
+	FW_SLV_TYPE_INV = 0,
+	FW_MST_TYPE_INV = 0,
+	FW_SLV_TYPE_BUS = 1,
+	FW_SLV_TYPE_TOP = 2,
+	FW_SLV_TYPE_CENTER = 3,
+	FW_SLV_TYPE_CCI = 4,
+	FW_SLV_TYPE_PHP = 5,
+	FW_SLV_TYPE_GPU = 6,
+	FW_SLV_TYPE_NPU = 7,
+	FW_SLV_TYPE_PMU = 8,
+	FW_MST_TYPE_SYS = 9,
+	FW_MST_TYPE_PMU = 10,
+};
+
+#define FW_ID(type, id)			\
+	((((type) & 0xff) << 16) | ((id) & 0xffff))
+
+#define FW_MST_ID(type, id)		FW_ID(type, id)
+#define FW_SLV_ID(type, id)		FW_ID(type, id)
+#define FW_GRP_ID(type, id)		FW_ID(type, id)
+
+/* group id */
+#define FW_GRP_ID_DDR_RGN(id)		FW_GRP_ID(FW_GRP_TYPE_DDR_RGN, id)
+#define FW_GRP_ID_SYSMEM_RGN(id)	FW_GRP_ID(FW_GRP_TYPE_SYSMEM_RGN, id)
+#define FW_GRP_ID_CBUF(id)		FW_GRP_ID(FW_GRP_TYPE_CBUF_RGN, id)
+#define FW_GRP_ID_SLV(id)		FW_GRP_ID(FW_GRP_TYPE_SLV, id)
+#define FW_GRP_ID_DM(id)		FW_GRP_ID(FW_GRP_TYPE_DM, id)
+
+#define FW_GRP_ID_SLV_CNT		8
+#define FW_GRP_ID_DM_CNT		8
+
+#define FW_GET_ID(id)			((id) & 0xffff)
+#define FW_GET_TYPE(id)			(((id) >> 16) & 0xff)
+
+#define FW_INVLID_MST_ID		FW_MST_ID(FW_MST_TYPE_INV, 0)
+#define FW_INVLID_SLV_ID		FW_SLV_ID(FW_SLV_TYPE_INV, 0)
+
+typedef struct {
+	uint32_t domain[FW_SGRF_MST_DOMAIN_CON_CNT];
+	uint32_t pmu_domain;
+	uint32_t bus_slv_grp[FW_SGRF_BUS_SLV_CON_CNT];
+	uint32_t top_slv_grp[FW_SGRF_TOP_SLV_CON_CNT];
+	uint32_t center_slv_grp[FW_SGRF_CENTER_SLV_CON_CNT];
+	uint32_t cci_slv_grp[FW_SGRF_CCI_SLV_CON_CNT];
+	uint32_t php_slv_grp[FW_SGRF_PHP_SLV_CON_CNT];
+	uint32_t gpu_slv_grp;
+	uint32_t npu_slv_grp[FW_SGRF_NPU_SLV_CON_CNT];
+	uint32_t pmu_slv_grp[FW_PMU_SGRF_SLV_CON_CNT];
+	uint32_t ddr_rgn[FW_SGRF_DDR_RGN_CNT];
+	uint32_t ddr_size;
+	uint32_t ddr_con;
+	uint32_t sysmem_rgn[FW_SGRF_SYSMEM_RGN_CNT];
+	uint32_t sysmem_con;
+	uint32_t cbuf_rgn[FW_SGRF_CBUF_RGN_CNT];
+	uint32_t cbuf_con;
+	uint32_t ddr_lookup[FW_SGRF_DDR_LOOKUP_CNT];
+	uint32_t sysmem_lookup[FW_SGRF_SYSMEM_LOOKUP_CNT];
+	uint32_t cbuf_lookup[FW_SGRF_CBUF_LOOKUP_CNT];
+	uint32_t slv_lookup[FW_SGRF_SLV_LOOKUP_CNT];
+	uint32_t pmu_slv_lookup[FW_PMU_SGRF_SLV_LOOKUP_CNT];
+} fw_config_t;
+
+static fw_config_t fw_config_buf;
+
+/****************************************************************************
+ * Access rights between domains and groups are as follows:
+ *
+ * 00: NS access,     S access
+ * 01: NS access,     S not access
+ * 10: NS not access, S access
+ * 11: NS not access, S not access
+ * |---------------------------------------------------------|
+ * |                 | d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7 |
+ * |---------------------------------------------------------|
+ * | slave g0        | 00 | 00 | 11 | 11 | 11 | 11 | 11 | 00 |
+ * |---------------------------------------------------------|
+ * | slave g1        | 10 | 11 | 11 | 11 | 11 | 11 | 11 | 10 |
+ * |---------------------------------------------------------|
+ * | slave g2~7      | 11 | 11 | 11 | 11 | 11 | 11 | 11 | 11 |
+ * |---------------------------------------------------------|
+ * | ddr region 0~15 | 10 | 11 | 11 | 11 | 11 | 11 | 11 | 10 |
+ * |---------------------------------------------------------|
+ * | sram region 0~3 | 10 | 11 | 11 | 11 | 11 | 11 | 11 | 10 |
+ * |---------------------------------------------------------|
+ * | cbuf region 0~7 | 10 | 11 | 11 | 11 | 11 | 11 | 11 | 10 |
+ * |---------------------------------------------------------|
+ *
+ * PS:
+ * Domain 0/1/7 NS/S can access group 0.
+ * Domain 0/1/7 NS and Domain1 NS/S can't access group 1, domain 0/7 S can access.
+ * Other domains NS/S can't access all groups.
+ *
+ * Domain 0/7 NS can't access ddr/sram/cbuf region and Domain 0/7 S can access.
+ * Other domains NS/S can't access ddr/sram/cbuf region.
+ *
+ ******************************************************************************/
+
+/* Masters in dm1 */
+static const int dm1_mst[] = {
+	FW_MST_ID(FW_MST_TYPE_SYS, 1), /* keylad_apbm */
+	FW_MST_ID(FW_MST_TYPE_SYS, 2), /* dft2apbm */
+	FW_MST_ID(FW_MST_TYPE_SYS, 11), /* dma2ddr */
+	FW_MST_ID(FW_MST_TYPE_SYS, 12), /* dmac0 */
+	FW_MST_ID(FW_MST_TYPE_SYS, 13), /* dmac1 */
+	FW_MST_ID(FW_MST_TYPE_SYS, 14), /* dmac2 */
+	FW_MST_ID(FW_MST_TYPE_SYS, 19), /* gpu */
+	FW_MST_ID(FW_MST_TYPE_SYS, 31), /* vop_m0 */
+	FW_MST_ID(FW_MST_TYPE_SYS, 32), /* vop_m1 */
+	FW_MST_ID(FW_MST_TYPE_SYS, 36), /* bus_mcu */
+	FW_MST_ID(FW_MST_TYPE_SYS, 38), /* npu_mcu */
+	FW_MST_ID(FW_MST_TYPE_SYS, 56), /* dap_lite */
+
+	FW_INVLID_MST_ID
+};
+
+/* Slaves in group1 */
+static const int sec_slv[] = {
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 28), /* crypto_s */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 29), /* keyladder_s */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 30), /* rkrng_s */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 33), /* jtag_lock */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 34), /* otp_s */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 35), /* otpmsk */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 37), /* scru_s */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 38), /* sys_sgrf */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 39), /* bootrom */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 41), /* wdts */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 44), /* sevice_secure */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 61), /* timers0_ch0~5 */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 62),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 63),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 64),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 65),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 66),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 67), /* timers1_ch0~5 */
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 68),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 69),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 70),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 71),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 72),
+	FW_SLV_ID(FW_SLV_TYPE_TOP, 73), /* sys_fw */
+
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 3),  /* ddr grf */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 4),  /* ddr ctl0 */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 5),  /* ddr ctl1 */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 6),  /* ddr phy0 */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 7),  /* ddr0 cru */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 8),  /* ddr phy1 */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 9),  /* ddr1 cru */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 15), /* ddr wdt */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 19), /* service ddr */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 58), /* ddr timer ch0 */
+	FW_SLV_ID(FW_SLV_TYPE_CENTER, 59), /* ddr timer ch1 */
+
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 1),	/* pmu mem */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 15), /* pmu1_scru */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 30), /* osc chk */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 31), /* pmu0_sgrf */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 32), /* pmu1_sgrf */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 34), /* scramble key */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 36), /* pmu remap */
+	FW_SLV_ID(FW_SLV_TYPE_PMU, 43), /* pmu fw */
+
+	FW_INVLID_SLV_ID
+};
+
+static void fw_buf_sys_mst_dm_cfg(int mst_id, uint32_t dm_id)
+{
+	int sft = (mst_id & 0x7) << 2;
+
+	fw_config_buf.domain[mst_id >> 3] &= ~(0xf << sft);
+	fw_config_buf.domain[mst_id >> 3] |= (dm_id & 0xf) << sft;
+}
+
+static void fw_buf_pmu_mst_dm_cfg(int mst_id, uint32_t dm_id)
+{
+	int sft = (mst_id & 0x7) << 2;
+
+	fw_config_buf.pmu_domain &= ~(0xf << sft);
+	fw_config_buf.pmu_domain |= (dm_id & 0xf) << sft;
+}
+
+void fw_buf_mst_dm_cfg(int mst_id, uint32_t dm_id)
+{
+	int type = FW_GET_TYPE(mst_id);
+
+	mst_id = FW_GET_ID(mst_id);
+
+	switch (type) {
+	case FW_MST_TYPE_SYS:
+		fw_buf_sys_mst_dm_cfg(mst_id, dm_id);
+		break;
+	case FW_MST_TYPE_PMU:
+		fw_buf_pmu_mst_dm_cfg(mst_id, dm_id);
+		break;
+
+	default:
+		ERROR("%s: unknown FW_DOMAIN_TYPE (0x%x)\n", __func__, type);
+		break;
+	}
+}
+
+static void fw_buf_ddr_lookup_cfg(int rgn_id, int dm_id, uint32_t priv)
+{
+	int sft = (dm_id << 1) + (rgn_id & 0x1) * 16;
+
+	fw_config_buf.ddr_lookup[rgn_id >> 1] &= ~(0x3 << sft);
+	fw_config_buf.ddr_lookup[rgn_id >> 1] |= (priv & 0x3) << sft;
+}
+
+static void fw_buf_sysmem_lookup_cfg(int rgn_id, int dm_id, uint32_t priv)
+{
+	int sft = (dm_id << 1) + (rgn_id & 0x1) * 16;
+
+	fw_config_buf.sysmem_lookup[rgn_id >> 1] &= ~(0x3 << sft);
+	fw_config_buf.sysmem_lookup[rgn_id >> 1] |= (priv & 0x3) << sft;
+}
+
+static void fw_buf_cbuf_lookup_cfg(int rgn_id, int dm_id, uint32_t priv)
+{
+	int sft = (dm_id << 1) + (rgn_id & 0x1) * 16;
+
+	fw_config_buf.cbuf_lookup[rgn_id >> 1] &= ~(0x3 << sft);
+	fw_config_buf.cbuf_lookup[rgn_id >> 1] |= (priv & 0x3) << sft;
+}
+
+static void fw_buf_slv_lookup_cfg(int grp_id, int dm_id, uint32_t priv)
+{
+	int sft = (dm_id << 1) + (grp_id & 0x1) * 16;
+
+	fw_config_buf.slv_lookup[grp_id >> 1] &= ~(0x3 << sft);
+	fw_config_buf.slv_lookup[grp_id >> 1] |= (priv & 0x3) << sft;
+}
+
+static void fw_buf_pmu_slv_lookup_cfg(int grp_id, int dm_id, uint32_t priv)
+{
+	int sft = (dm_id << 1) + (grp_id & 0x1) * 16;
+
+	fw_config_buf.pmu_slv_lookup[grp_id >> 1] &= ~(0x3 << sft);
+	fw_config_buf.pmu_slv_lookup[grp_id >> 1] |= (priv & 0x3) << sft;
+}
+
+void fw_buf_grp_lookup_cfg(int grp_id, int dm_id, uint32_t priv)
+{
+	uint32_t type = FW_GET_TYPE(grp_id);
+
+	grp_id = FW_GET_ID(grp_id);
+
+	switch (type) {
+	case FW_GRP_TYPE_DDR_RGN:
+		fw_buf_ddr_lookup_cfg(grp_id, dm_id, priv);
+		break;
+	case FW_GRP_TYPE_SYSMEM_RGN:
+		fw_buf_sysmem_lookup_cfg(grp_id, dm_id, priv);
+		break;
+	case FW_GRP_TYPE_CBUF_RGN:
+		fw_buf_cbuf_lookup_cfg(grp_id, dm_id, priv);
+		break;
+	case FW_GRP_TYPE_SLV:
+		fw_buf_slv_lookup_cfg(grp_id, dm_id, priv);
+		fw_buf_pmu_slv_lookup_cfg(grp_id, dm_id, priv);
+		break;
+
+	default:
+		ERROR("%s: unknown FW_LOOKUP_TYPE (0x%x)\n", __func__, type);
+		break;
+	}
+}
+
+static void fw_buf_bus_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.bus_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.bus_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_top_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.top_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.top_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_center_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.center_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.center_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_cci_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.cci_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.cci_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_php_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.php_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.php_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_gpu_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.gpu_slv_grp &= ~(0xf << sft);
+	fw_config_buf.gpu_slv_grp |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_npu_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.npu_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.npu_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+static void fw_buf_pmu_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int sft = slv_id % 5 << 2;
+
+	fw_config_buf.pmu_slv_grp[slv_id / 5] &= ~(0xf << sft);
+	fw_config_buf.pmu_slv_grp[slv_id / 5] |= (grp_id & 0xf) << sft;
+}
+
+void fw_buf_slv_grp_cfg(int slv_id, int grp_id)
+{
+	int type = FW_GET_TYPE(slv_id);
+
+	slv_id = FW_GET_ID(slv_id);
+	grp_id = FW_GET_ID(grp_id);
+
+	switch (type) {
+	case FW_SLV_TYPE_BUS:
+		fw_buf_bus_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_TOP:
+		fw_buf_top_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_CENTER:
+		fw_buf_center_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_CCI:
+		fw_buf_cci_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_PHP:
+		fw_buf_php_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_GPU:
+		fw_buf_gpu_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_NPU:
+		fw_buf_npu_slv_grp_cfg(slv_id, grp_id);
+		break;
+	case FW_SLV_TYPE_PMU:
+		fw_buf_pmu_slv_grp_cfg(slv_id, grp_id);
+		break;
+
+	default:
+		ERROR("%s: unknown FW_SLV_TYPE (0x%x)\n", __func__, type);
+		break;
+	}
+}
+
+void fw_buf_add_msts(const int *mst_ids, int dm_id)
+{
+	int i;
+
+	for (i = 0; FW_GET_TYPE(mst_ids[i]) != FW_INVLID_SLV_ID; i++)
+		fw_buf_mst_dm_cfg(mst_ids[i], dm_id);
+}
+
+void fw_buf_add_slvs(const int *slv_ids, int grp_id)
+{
+	int i;
+
+	for (i = 0; FW_GET_TYPE(slv_ids[i]) != FW_INVLID_SLV_ID; i++)
+		fw_buf_slv_grp_cfg(slv_ids[i], grp_id);
+}
+
+/* unit: Mb */
+void fw_buf_ddr_size_cfg(uint64_t base_mb, uint64_t top_mb, int id)
+{
+	fw_config_buf.ddr_size = RG_MAP_SECURE(top_mb, base_mb);
+	fw_config_buf.ddr_con |= BIT(16);
+}
+
+/* unit: Mb */
+void fw_buf_ddr_rgn_cfg(uint64_t base_mb, uint64_t top_mb, int rgn_id)
+{
+	fw_config_buf.ddr_rgn[rgn_id] = RG_MAP_SECURE(top_mb, base_mb);
+	fw_config_buf.ddr_con |= BIT(rgn_id);
+}
+
+/* Unit: kb */
+void fw_buf_sysmem_rgn_cfg(uint64_t base_kb, uint64_t top_kb, int rgn_id)
+{
+	fw_config_buf.sysmem_rgn[rgn_id] = RG_MAP_SRAM_SECURE(top_kb, base_kb);
+	fw_config_buf.sysmem_con |= BIT(rgn_id);
+}
+
+static void fw_domain_init(void)
+{
+	int i;
+
+	/* select to domain0 by default */
+	for (i = 0; i < FW_SGRF_MST_DOMAIN_CON_CNT; i++)
+		fw_config_buf.domain[i] = 0x0;
+
+	/* select to domain0 by default */
+	fw_config_buf.pmu_domain = 0x0;
+}
+
+static void fw_slv_grp_init(void)
+{
+	int i;
+
+	/* select to group0 by default */
+	for (i = 0; i < FW_SGRF_BUS_SLV_CON_CNT; i++)
+		fw_config_buf.bus_slv_grp[i] = 0x0;
+
+	for (i = 0; i < FW_SGRF_TOP_SLV_CON_CNT; i++)
+		fw_config_buf.top_slv_grp[i] = 0x0;
+
+	for (i = 0; i < FW_SGRF_CENTER_SLV_CON_CNT; i++)
+		fw_config_buf.center_slv_grp[i] = 0x0;
+
+	for (i = 0; i < FW_SGRF_CCI_SLV_CON_CNT; i++)
+		fw_config_buf.cci_slv_grp[i] = 0x0;
+
+	for (i = 0; i < FW_SGRF_PHP_SLV_CON_CNT; i++)
+		fw_config_buf.php_slv_grp[i] = 0x0;
+
+	fw_config_buf.gpu_slv_grp = 0x0;
+
+	for (i = 0; i < FW_SGRF_NPU_SLV_CON_CNT; i++)
+		fw_config_buf.npu_slv_grp[i] = 0x0;
+}
+
+static void fw_region_init(void)
+{
+	/* Use FW_DDR_RGN0_REG to config 1024~1025M space to secure */
+	fw_buf_ddr_rgn_cfg(1024, 1025, 0);
+
+	/* Use FW_SYSMEM_RGN0_REG to config 0~32k space to secure */
+	fw_buf_sysmem_rgn_cfg(0, 32, 0);
+}
+
+static void fw_lookup_init(void)
+{
+	int i;
+
+	/*
+	 * Domain 0/7 NS can't access ddr/sram/cbuf region and Domain 0/7 S can access.
+	 * Other domains NS/S can't access ddr/sram/cbuf region.
+	 */
+	for (i = 0; i < FW_SGRF_DDR_LOOKUP_CNT; i++)
+		fw_config_buf.ddr_lookup[i] = 0xbffebffe;
+
+	for (i = 0; i < FW_SGRF_SYSMEM_LOOKUP_CNT; i++)
+		fw_config_buf.sysmem_lookup[i] = 0xbffebffe;
+
+	for (i = 0; i < FW_SGRF_CBUF_LOOKUP_CNT; i++)
+		fw_config_buf.cbuf_lookup[i] = 0xbffebffe;
+
+	/*
+	 * Domain 0/1/7 NS/S can access group 0.
+	 * Domain 0/1/7 NS and Domain1 NS/S can't access group 1, domain 0/7 S can access.
+	 * Other domains NS/S can't access all groups.
+	 */
+	fw_config_buf.slv_lookup[0] = 0xbffe3ff0;
+	fw_config_buf.slv_lookup[1] = 0xffffffff;
+	fw_config_buf.slv_lookup[2] = 0xffffffff;
+	fw_config_buf.slv_lookup[3] = 0xffffffff;
+
+	/*
+	 * Domain 0/1/7 NS/S can access group 0.
+	 * Domain 0/1/7 NS and Domain1 NS/S can't access group 1, domain 0/7 S can access.
+	 * Other domains NS/S can't access all groups.
+	 */
+	fw_config_buf.pmu_slv_lookup[0] = 0xbffe3ff0;
+	fw_config_buf.pmu_slv_lookup[1] = 0xffffffff;
+	fw_config_buf.pmu_slv_lookup[2] = 0xffffffff;
+	fw_config_buf.pmu_slv_lookup[3] = 0xffffffff;
+}
+
+static void fw_config_buf_flush(void)
+{
+	int i;
+
+	/* domain */
+	for (i = 0; i < FW_SGRF_MST_DOMAIN_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_MST_DOMAIN_CON(i),
+			      fw_config_buf.domain[i]);
+
+	mmio_write_32(PMU1SGRF_FW_BASE + FW_PMU_SGRF_DOMAIN_CON,
+		      fw_config_buf.pmu_domain);
+
+	/* slave group */
+	for (i = 0; i < FW_SGRF_BUS_SLV_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_BUS_SLV_CON(i),
+			      fw_config_buf.bus_slv_grp[i]);
+
+	for (i = 0; i < FW_SGRF_TOP_SLV_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_TOP_SLV_CON(i),
+			      fw_config_buf.top_slv_grp[i]);
+
+	for (i = 0; i < FW_SGRF_CENTER_SLV_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CENTER_SLV_CON(i),
+			      fw_config_buf.center_slv_grp[i]);
+
+	for (i = 0; i < FW_SGRF_CCI_SLV_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CCI_SLV_CON(i),
+			      fw_config_buf.cci_slv_grp[i]);
+
+	for (i = 0; i < FW_SGRF_PHP_SLV_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_PHP_SLV_CON(i),
+			      fw_config_buf.php_slv_grp[i]);
+
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_GPU_SLV_CON,
+		      fw_config_buf.gpu_slv_grp);
+
+	for (i = 0; i < FW_SGRF_NPU_SLV_CON_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_NPU_SLV_CON(i),
+			      fw_config_buf.npu_slv_grp[i]);
+
+	for (i = 0; i < FW_PMU_SGRF_SLV_CON_CNT; i++)
+		mmio_write_32(PMU1SGRF_FW_BASE + FW_PMU_SGRF_SLV_CON(i),
+			      fw_config_buf.pmu_slv_grp[i]);
+
+	/* region */
+	for (i = 0; i < FW_SGRF_DDR_RGN_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_DDR_RGN(i),
+			      fw_config_buf.ddr_rgn[i]);
+
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_DDR_SIZE, fw_config_buf.ddr_size);
+
+	for (i = 0; i < FW_SGRF_SYSMEM_RGN_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SYSMEM_RGN(i),
+			      fw_config_buf.sysmem_rgn[i]);
+
+	for (i = 0; i < FW_SGRF_CBUF_RGN_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CBUF_RGN(i),
+			      fw_config_buf.cbuf_rgn[i]);
+
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_DDR_CON, fw_config_buf.ddr_con);
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SYSMEM_CON, fw_config_buf.sysmem_con);
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CBUF_CON, fw_config_buf.cbuf_con);
+
+	dsb();
+	isb();
+
+	/* lookup */
+	for (i = 0; i < FW_SGRF_DDR_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_DDR_LOOKUP(i),
+			      fw_config_buf.ddr_lookup[i]);
+
+	for (i = 0; i < FW_SGRF_SYSMEM_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SYSMEM_LOOKUP(i),
+			      fw_config_buf.sysmem_lookup[i]);
+
+	for (i = 0; i < FW_SGRF_CBUF_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CBUF_LOOKUP(i),
+			      fw_config_buf.cbuf_lookup[i]);
+
+	for (i = 0; i < FW_SGRF_SLV_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SLV_LOOKUP(i),
+			      fw_config_buf.slv_lookup[i]);
+
+	for (i = 0; i < FW_PMU_SGRF_SLV_LOOKUP_CNT; i++)
+		mmio_write_32(PMU1SGRF_FW_BASE + FW_PMU_SGRF_SLV_LOOKUP(i),
+			      fw_config_buf.pmu_slv_lookup[i]);
+
+	dsb();
+	isb();
+}
+
+static __pmusramfunc void pmusram_udelay(uint32_t us)
+{
+	uint64_t orig;
+	uint64_t to_wait;
+
+	orig = read_cntpct_el0();
+	to_wait = read_cntfrq_el0() * us / 1000000;
+
+	while (read_cntpct_el0() - orig <= to_wait)
+		;
+}
+
+__pmusramfunc void pmusram_fw_update_msk(uint32_t msk)
+{
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0,
+		      BITS_WITH_WMASK(0, 0x3ff, 0));
+	dsb();
+
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0,
+		      BITS_WITH_WMASK(msk, msk, 0));
+	dsb();
+	isb();
+	pmusram_udelay(20);
+	dsb();
+	isb();
+}
+
+__pmusramfunc void pmusram_all_fw_bypass(void)
+{
+	int i;
+
+	/* disable regions */
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_DDR_CON, 0);
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SYSMEM_CON, 0);
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CBUF_CON, 0);
+
+	for (i = 0; i < FW_SGRF_DDR_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_DDR_LOOKUP(i), 0x0);
+
+	for (i = 0; i < FW_SGRF_SYSMEM_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SYSMEM_LOOKUP(i), 0x0);
+
+	for (i = 0; i < FW_SGRF_CBUF_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_CBUF_LOOKUP(i), 0x0);
+
+	for (i = 0; i < FW_SGRF_SLV_LOOKUP_CNT; i++)
+		mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_SLV_LOOKUP(i), 0x0);
+
+	for (i = 0; i < FW_PMU_SGRF_SLV_LOOKUP_CNT; i++)
+		mmio_write_32(PMU1SGRF_FW_BASE + FW_PMU_SGRF_SLV_LOOKUP(i), 0x0);
+
+	dsb();
+
+	pmusram_fw_update_msk(0x3ff);
+}
+
+void fw_init(void)
+{
+	/* Enable all fw auto-update */
+	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1, 0x03ff03ff);
+
+	pmusram_all_fw_bypass();
+
+	fw_domain_init();
+	fw_slv_grp_init();
+	fw_region_init();
+
+	fw_buf_add_slvs(sec_slv, 1);
+	fw_buf_add_msts(dm1_mst, 1);
+
+	fw_lookup_init();
+
+	fw_config_buf_flush();
+	pmusram_fw_update_msk(0x3ff);
+}
diff --git a/plat/rockchip/rk3576/drivers/secure/firewall.h b/plat/rockchip/rk3576/drivers/secure/firewall.h
new file mode 100644
index 0000000..7b13071
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/secure/firewall.h
@@ -0,0 +1,499 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __FIREWALL_H__
+#define __FIREWALL_H__
+
+#include <plat_private.h>
+
+/* FW SGRF */
+#define FW_SGRF_MST_DOMAIN_CON(i)	((i) * 4)
+#define FW_SGRF_MST_DOMAIN_CON_CNT	8
+#define FW_SGRF_DDR_RGN(i)		(0x0100 + (i) * 4)
+#define FW_SGRF_DDR_RGN_CNT		16
+#define FW_SGRF_DDR_LOOKUP(i)		(0x0140 + (i) * 0x4)
+#define FW_SGRF_DDR_LOOKUP_CNT		8
+#define FW_SGRF_DDR_SIZE		0x0160
+#define FW_SGRF_DDR_CON			0x0168
+#define FW_SGRF_SYSMEM_RGN(i)		(0x0200 + (i) * 4)
+#define FW_SGRF_SYSMEM_RGN_CNT		4
+#define FW_SGRF_SYSMEM_LOOKUP(i)	(0x0210 + (i) * 4)
+#define FW_SGRF_SYSMEM_LOOKUP_CNT	2
+#define FW_SGRF_SYSMEM_CON		0x0218
+#define FW_SGRF_CBUF_RGN(i)		(0x0300 + (i) * 4)
+#define FW_SGRF_CBUF_RGN_CNT		8
+#define FW_SGRF_CBUF_LOOKUP(i)		(0x0320 + (i) * 4)
+#define FW_SGRF_CBUF_LOOKUP_CNT		4
+#define FW_SGRF_CBUF_CON		0x0330
+#define FW_SGRF_SLV_LOOKUP(i)		(0x0400 + (i) * 4)
+#define FW_SGRF_SLV_LOOKUP_CNT		4
+#define FW_SGRF_BUS_SLV_CON(i)		(0x0500 + (i) * 4)
+#define FW_SGRF_BUS_SLV_CON_CNT		25
+#define FW_SGRF_BUS_SLV_STAT		0x0580
+#define FW_SGRF_TOP_SLV_CON(i)		(0x0600 + (i) * 4)
+#define FW_SGRF_TOP_SLV_CON_CNT		16
+#define FW_SGRF_TOP_SLV_STAT		0x0680
+#define FW_SGRF_CENTER_SLV_CON(i)	(0x0700 + (i) * 4)
+#define FW_SGRF_CENTER_SLV_CON_CNT	13
+#define FW_SGRF_CCI_SLV_CON(i)		(0x0800 + (i) * 4)
+#define FW_SGRF_CCI_SLV_CON_CNT		3
+#define FW_SGRF_PHP_SLV_CON(i)		(0x0900 + (i) * 4)
+#define FW_SGRF_PHP_SLV_CON_CNT		4
+#define FW_SGRF_PHP_SLV_STAT		0x0940
+#define FW_SGRF_GPU_SLV_CON		0x0980
+#define FW_SGRF_NPU_SLV_CON(i)		(0x09a0 + (i) * 4)
+#define FW_SGRF_NPU_SLV_CON_CNT		2
+#define FW_SGRF_STATCLR_CON0		0x0a00
+#define FW_SGRF_KEYUPD_CON0		0x0a80
+#define FW_SGRF_KEYUPD_CON1		0x0a84
+#define FW_SGRF_KEYUPD_STAT		0x0ab0
+
+/* FW PMUSGRF */
+#define FW_PMU_SGRF_SLV_CON(i)		((i) * 4)
+#define FW_PMU_SGRF_SLV_CON_CNT		9
+#define FW_PMU_SGRF_SLV_LOOKUP(i)	(0x0080 + (i) * 0x4)
+#define FW_PMU_SGRF_SLV_LOOKUP_CNT	4
+#define FW_PMU_SGRF_DOMAIN_CON		0x00a0
+#define FW_PMU_SGRF_SLV_STAT		0x00c0
+
+/* master id */
+#define FW_MST_ID_USB0			FW_MST_ID(FW_MST_TYPE_SYS, 0)
+#define FW_MST_ID_KEYLAD_APB		FW_MST_ID(FW_MST_TYPE_SYS, 1)
+#define FW_MST_ID_DFT2APB		FW_MST_ID(FW_MST_TYPE_SYS, 2)
+#define FW_MST_ID_PCIE0			FW_MST_ID(FW_MST_TYPE_SYS, 3)
+#define FW_MST_ID_PCIE1			FW_MST_ID(FW_MST_TYPE_SYS, 4)
+#define FW_MST_ID_SATA0			FW_MST_ID(FW_MST_TYPE_SYS, 6)
+#define FW_MST_ID_SATA1			FW_MST_ID(FW_MST_TYPE_SYS, 7)
+#define FW_MST_ID_CRYPTO		FW_MST_ID(FW_MST_TYPE_SYS, 8)
+#define FW_MST_ID_FLEXBUS		FW_MST_ID(FW_MST_TYPE_SYS, 9)
+#define FW_MST_ID_DECOM			FW_MST_ID(FW_MST_TYPE_SYS, 10)
+#define FW_MST_ID_DMA2DDR		FW_MST_ID(FW_MST_TYPE_SYS, 11)
+#define FW_MST_ID_DMAC0			FW_MST_ID(FW_MST_TYPE_SYS, 12)
+#define FW_MST_ID_DMAC1			FW_MST_ID(FW_MST_TYPE_SYS, 13)
+#define FW_MST_ID_DMAC2			FW_MST_ID(FW_MST_TYPE_SYS, 14)
+#define FW_MST_ID_EBC			FW_MST_ID(FW_MST_TYPE_SYS, 15)
+#define FW_MST_ID_EMMC			FW_MST_ID(FW_MST_TYPE_SYS, 16)
+#define FW_MST_ID_GMAC0			FW_MST_ID(FW_MST_TYPE_SYS, 17)
+#define FW_MST_ID_GMAC1			FW_MST_ID(FW_MST_TYPE_SYS, 18)
+#define FW_MST_ID_GPU			FW_MST_ID(FW_MST_TYPE_SYS, 19)
+#define FW_MST_ID_HDCP0			FW_MST_ID(FW_MST_TYPE_SYS, 20)
+#define FW_MST_ID_HDCP1			FW_MST_ID(FW_MST_TYPE_SYS, 21)
+#define FW_MST_ID_ISP			FW_MST_ID(FW_MST_TYPE_SYS, 22)
+#define FW_MST_ID_RGA0			FW_MST_ID(FW_MST_TYPE_SYS, 23)
+#define FW_MST_ID_RGA1			FW_MST_ID(FW_MST_TYPE_SYS, 24)
+#define FW_MST_ID_JPEG			FW_MST_ID(FW_MST_TYPE_SYS, 25)
+#define FW_MST_ID_RKVDEC		FW_MST_ID(FW_MST_TYPE_SYS, 26)
+#define FW_MST_ID_VEPU0			FW_MST_ID(FW_MST_TYPE_SYS, 27)
+#define FW_MST_ID_UFSHC			FW_MST_ID(FW_MST_TYPE_SYS, 28)
+#define FW_MST_ID_VDPP			FW_MST_ID(FW_MST_TYPE_SYS, 29)
+#define FW_MST_ID_VICAP			FW_MST_ID(FW_MST_TYPE_SYS, 30)
+#define FW_MST_ID_VOP_M0		FW_MST_ID(FW_MST_TYPE_SYS, 31)
+#define FW_MST_ID_VOP_M1		FW_MST_ID(FW_MST_TYPE_SYS, 32)
+#define FW_MST_ID_VPSS			FW_MST_ID(FW_MST_TYPE_SYS, 33)
+#define FW_MST_ID_FSPI0			FW_MST_ID(FW_MST_TYPE_SYS, 34)
+#define FW_MST_ID_FSPI1			FW_MST_ID(FW_MST_TYPE_SYS, 35)
+#define FW_MST_ID_BUS_MCU		FW_MST_ID(FW_MST_TYPE_SYS, 36)
+#define FW_MST_ID_DDR_MCU		FW_MST_ID(FW_MST_TYPE_SYS, 37)
+#define FW_MST_ID_NPU_MCU		FW_MST_ID(FW_MST_TYPE_SYS, 38)
+#define FW_MST_ID_CAN0			FW_MST_ID(FW_MST_TYPE_SYS, 39)
+#define FW_MST_ID_CAN1			FW_MST_ID(FW_MST_TYPE_SYS, 40)
+#define FW_MST_ID_SDIO			FW_MST_ID(FW_MST_TYPE_SYS, 41)
+#define FW_MST_ID_SDMMC0		FW_MST_ID(FW_MST_TYPE_SYS, 42)
+#define FW_MST_ID_USB1			FW_MST_ID(FW_MST_TYPE_SYS, 43)
+#define FW_MST_ID_NPU_M0		FW_MST_ID(FW_MST_TYPE_SYS, 44)
+#define FW_MST_ID_NPU_M0RO		FW_MST_ID(FW_MST_TYPE_SYS, 45)
+#define FW_MST_ID_NPU_M1		FW_MST_ID(FW_MST_TYPE_SYS, 46)
+#define FW_MST_ID_NPU_M1RO		FW_MST_ID(FW_MST_TYPE_SYS, 47)
+#define FW_MST_ID_A53_0			FW_MST_ID(FW_MST_TYPE_SYS, 48)
+#define FW_MST_ID_A53_1			FW_MST_ID(FW_MST_TYPE_SYS, 49)
+#define FW_MST_ID_A53_2			FW_MST_ID(FW_MST_TYPE_SYS, 50)
+#define FW_MST_ID_A53_3			FW_MST_ID(FW_MST_TYPE_SYS, 51)
+#define FW_MST_ID_A72_0			FW_MST_ID(FW_MST_TYPE_SYS, 52)
+#define FW_MST_ID_A72_1			FW_MST_ID(FW_MST_TYPE_SYS, 53)
+#define FW_MST_ID_A72_2			FW_MST_ID(FW_MST_TYPE_SYS, 54)
+#define FW_MST_ID_A72_3			FW_MST_ID(FW_MST_TYPE_SYS, 55)
+#define FW_MST_ID_DAP_LITE		FW_MST_ID(FW_MST_TYPE_SYS, 56)
+#define FW_MST_ID_VEPU1			FW_MST_ID(FW_MST_TYPE_SYS, 57)
+#define FW_MST_ID_SYS_CNT		64
+
+#define FW_MST_ID_PMU_MCU		FW_MST_ID(FW_MST_TYPE_PMU, 0)
+#define FW_MST_ID_VDMA			FW_MST_ID(FW_MST_TYPE_PMU, 1)
+#define FW_MST_ID_PMU_CNT		8
+
+/* slave id */
+#define FW_SLV_ID_CAN0			FW_SLV_ID(FW_SLV_TYPE_BUS, 0)
+#define FW_SLV_ID_CAN1			FW_SLV_ID(FW_SLV_TYPE_BUS, 1)
+#define FW_SLV_ID_I3C0			FW_SLV_ID(FW_SLV_TYPE_BUS, 2)
+#define FW_SLV_ID_I3C1			FW_SLV_ID(FW_SLV_TYPE_BUS, 3)
+#define FW_SLV_ID_BUS_IOC		FW_SLV_ID(FW_SLV_TYPE_BUS, 4)
+#define FW_SLV_ID_COMBO_PIPE_PHY0	FW_SLV_ID(FW_SLV_TYPE_BUS, 5)
+#define FW_SLV_ID_COMBO_PIPE_PHY1	FW_SLV_ID(FW_SLV_TYPE_BUS, 6)
+#define FW_SLV_ID_CRU			FW_SLV_ID(FW_SLV_TYPE_BUS, 7)
+#define FW_SLV_ID_DECOM			FW_SLV_ID(FW_SLV_TYPE_BUS, 8)
+#define FW_SLV_ID_CRU_PVTPLL		FW_SLV_ID(FW_SLV_TYPE_BUS, 9)
+#define FW_SLV_ID_I2C1			FW_SLV_ID(FW_SLV_TYPE_BUS, 13)
+#define FW_SLV_ID_I2C2			FW_SLV_ID(FW_SLV_TYPE_BUS, 14)
+#define FW_SLV_ID_I2C3			FW_SLV_ID(FW_SLV_TYPE_BUS, 15)
+#define FW_SLV_ID_I2C4			FW_SLV_ID(FW_SLV_TYPE_BUS, 16)
+#define FW_SLV_ID_I2C5			FW_SLV_ID(FW_SLV_TYPE_BUS, 17)
+#define FW_SLV_ID_I2C6			FW_SLV_ID(FW_SLV_TYPE_BUS, 18)
+#define FW_SLV_ID_I2C7			FW_SLV_ID(FW_SLV_TYPE_BUS, 19)
+#define FW_SLV_ID_I2C8			FW_SLV_ID(FW_SLV_TYPE_BUS, 20)
+#define FW_SLV_ID_I2C9			FW_SLV_ID(FW_SLV_TYPE_BUS, 21)
+#define FW_SLV_ID_INTMUX2BUS		FW_SLV_ID(FW_SLV_TYPE_BUS, 22)
+#define FW_SLV_ID_INTMUX2DDR		FW_SLV_ID(FW_SLV_TYPE_BUS, 23)
+#define FW_SLV_ID_INTMUX2PMU		FW_SLV_ID(FW_SLV_TYPE_BUS, 24)
+#define FW_SLV_ID_PPLL_CRU		FW_SLV_ID(FW_SLV_TYPE_BUS, 25)
+#define FW_SLV_ID_COMBO_PIPE_PHY0_GRF	FW_SLV_ID(FW_SLV_TYPE_BUS, 26)
+#define FW_SLV_ID_COMBO_PIPE_PHY1_GRF	FW_SLV_ID(FW_SLV_TYPE_BUS, 27)
+#define FW_SLV_ID_PMU2			FW_SLV_ID(FW_SLV_TYPE_BUS, 28)
+#define FW_SLV_ID_SARADC		FW_SLV_ID(FW_SLV_TYPE_BUS, 32)
+#define FW_SLV_ID_SPI0			FW_SLV_ID(FW_SLV_TYPE_BUS, 33)
+#define FW_SLV_ID_SPI1			FW_SLV_ID(FW_SLV_TYPE_BUS, 34)
+#define FW_SLV_ID_SPI2			FW_SLV_ID(FW_SLV_TYPE_BUS, 35)
+#define FW_SLV_ID_SPI3			FW_SLV_ID(FW_SLV_TYPE_BUS, 36)
+#define FW_SLV_ID_SPI4			FW_SLV_ID(FW_SLV_TYPE_BUS, 37)
+#define FW_SLV_ID_SYS_GRF		FW_SLV_ID(FW_SLV_TYPE_BUS, 38)
+#define FW_SLV_ID_TSADC			FW_SLV_ID(FW_SLV_TYPE_BUS, 41)
+#define FW_SLV_ID_UART0			FW_SLV_ID(FW_SLV_TYPE_BUS, 42)
+#define FW_SLV_ID_UART10		FW_SLV_ID(FW_SLV_TYPE_BUS, 43)
+#define FW_SLV_ID_UART11		FW_SLV_ID(FW_SLV_TYPE_BUS, 44)
+#define FW_SLV_ID_UART2			FW_SLV_ID(FW_SLV_TYPE_BUS, 45)
+#define FW_SLV_ID_UART3			FW_SLV_ID(FW_SLV_TYPE_BUS, 46)
+#define FW_SLV_ID_UART4			FW_SLV_ID(FW_SLV_TYPE_BUS, 47)
+#define FW_SLV_ID_UART5			FW_SLV_ID(FW_SLV_TYPE_BUS, 48)
+#define FW_SLV_ID_UART6			FW_SLV_ID(FW_SLV_TYPE_BUS, 49)
+#define FW_SLV_ID_UART7			FW_SLV_ID(FW_SLV_TYPE_BUS, 50)
+#define FW_SLV_ID_UART8			FW_SLV_ID(FW_SLV_TYPE_BUS, 51)
+#define FW_SLV_ID_UART9			FW_SLV_ID(FW_SLV_TYPE_BUS, 52)
+#define FW_SLV_ID_VCCIO0_1_3_IOC	FW_SLV_ID(FW_SLV_TYPE_BUS, 53)
+#define FW_SLV_ID_VCCIO2_4_5_IOC	FW_SLV_ID(FW_SLV_TYPE_BUS, 54)
+#define FW_SLV_ID_BUS_WDT		FW_SLV_ID(FW_SLV_TYPE_BUS, 55)
+#define FW_SLV_ID_WDT_NS		FW_SLV_ID(FW_SLV_TYPE_BUS, 56)
+#define FW_SLV_ID_DMAC0_NS		FW_SLV_ID(FW_SLV_TYPE_BUS, 57)
+#define FW_SLV_ID_DMAC1_NS		FW_SLV_ID(FW_SLV_TYPE_BUS, 58)
+#define FW_SLV_ID_DMAC2_NS		FW_SLV_ID(FW_SLV_TYPE_BUS, 59)
+#define FW_SLV_ID_DMAC0_S		FW_SLV_ID(FW_SLV_TYPE_BUS, 60)
+#define FW_SLV_ID_DMAC1_S		FW_SLV_ID(FW_SLV_TYPE_BUS, 61)
+#define FW_SLV_ID_DMAC2_S		FW_SLV_ID(FW_SLV_TYPE_BUS, 62)
+#define FW_SLV_ID_GIC400		FW_SLV_ID(FW_SLV_TYPE_BUS, 63)
+#define FW_SLV_ID_SERVICE_BUS		FW_SLV_ID(FW_SLV_TYPE_BUS, 64)
+#define FW_SLV_ID_SPINLOCK		FW_SLV_ID(FW_SLV_TYPE_BUS, 65)
+#define FW_SLV_ID_MAILBOX_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 66)
+#define FW_SLV_ID_MAILBOX_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 67)
+#define FW_SLV_ID_MAILBOX_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 68)
+#define FW_SLV_ID_MAILBOX_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 69)
+#define FW_SLV_ID_MAILBOX_CH4		FW_SLV_ID(FW_SLV_TYPE_BUS, 70)
+#define FW_SLV_ID_MAILBOX_CH5		FW_SLV_ID(FW_SLV_TYPE_BUS, 71)
+#define FW_SLV_ID_MAILBOX_CH6		FW_SLV_ID(FW_SLV_TYPE_BUS, 72)
+#define FW_SLV_ID_MAILBOX_CH7		FW_SLV_ID(FW_SLV_TYPE_BUS, 73)
+#define FW_SLV_ID_MAILBOX_CH8		FW_SLV_ID(FW_SLV_TYPE_BUS, 74)
+#define FW_SLV_ID_MAILBOX_CH9		FW_SLV_ID(FW_SLV_TYPE_BUS, 75)
+#define FW_SLV_ID_MAILBOX_CH10		FW_SLV_ID(FW_SLV_TYPE_BUS, 76)
+#define FW_SLV_ID_MAILBOX_CH11		FW_SLV_ID(FW_SLV_TYPE_BUS, 77)
+#define FW_SLV_ID_MAILBOX_CH12		FW_SLV_ID(FW_SLV_TYPE_BUS, 78)
+#define FW_SLV_ID_MAILBOX_CH13		FW_SLV_ID(FW_SLV_TYPE_BUS, 79)
+#define FW_SLV_ID_PWM1_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 82)
+#define FW_SLV_ID_PWM1_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 83)
+#define FW_SLV_ID_PWM1_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 84)
+#define FW_SLV_ID_PWM1_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 85)
+#define FW_SLV_ID_PWM1_CH4		FW_SLV_ID(FW_SLV_TYPE_BUS, 86)
+#define FW_SLV_ID_PWM1_CH5		FW_SLV_ID(FW_SLV_TYPE_BUS, 87)
+#define FW_SLV_ID_PWM2_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 88)
+#define FW_SLV_ID_PWM2_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 89)
+#define FW_SLV_ID_PWM2_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 90)
+#define FW_SLV_ID_PWM2_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 91)
+#define FW_SLV_ID_PWM2_CH4		FW_SLV_ID(FW_SLV_TYPE_BUS, 92)
+#define FW_SLV_ID_PWM2_CH5		FW_SLV_ID(FW_SLV_TYPE_BUS, 93)
+#define FW_SLV_ID_PWM2_CH6		FW_SLV_ID(FW_SLV_TYPE_BUS, 94)
+#define FW_SLV_ID_PWM2_CH7		FW_SLV_ID(FW_SLV_TYPE_BUS, 95)
+#define FW_SLV_ID_TIMER_NS_0_CH0	FW_SLV_ID(FW_SLV_TYPE_BUS, 96)
+#define FW_SLV_ID_TIMER_NS_0_CH1	FW_SLV_ID(FW_SLV_TYPE_BUS, 97)
+#define FW_SLV_ID_TIMER_NS_0_CH2	FW_SLV_ID(FW_SLV_TYPE_BUS, 98)
+#define FW_SLV_ID_TIMER_NS_0_CH3	FW_SLV_ID(FW_SLV_TYPE_BUS, 99)
+#define FW_SLV_ID_TIMER_NS_0_CH4	FW_SLV_ID(FW_SLV_TYPE_BUS, 100)
+#define FW_SLV_ID_TIMER_NS_0_CH5	FW_SLV_ID(FW_SLV_TYPE_BUS, 101)
+#define FW_SLV_ID_TIMER_NS_1_CH0	FW_SLV_ID(FW_SLV_TYPE_BUS, 102)
+#define FW_SLV_ID_TIMER_NS_1_CH1	FW_SLV_ID(FW_SLV_TYPE_BUS, 103)
+#define FW_SLV_ID_TIMER_NS_1_CH2	FW_SLV_ID(FW_SLV_TYPE_BUS, 104)
+#define FW_SLV_ID_TIMER_NS_1_CH3	FW_SLV_ID(FW_SLV_TYPE_BUS, 105)
+#define FW_SLV_ID_TIMER_NS_1_CH4	FW_SLV_ID(FW_SLV_TYPE_BUS, 106)
+#define FW_SLV_ID_TIMER_NS_1_CH5	FW_SLV_ID(FW_SLV_TYPE_BUS, 107)
+#define FW_SLV_ID_GPIO1_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 108)
+#define FW_SLV_ID_GPIO1_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 109)
+#define FW_SLV_ID_GPIO1_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 110)
+#define FW_SLV_ID_GPIO1_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 111)
+#define FW_SLV_ID_GPIO2_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 112)
+#define FW_SLV_ID_GPIO2_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 113)
+#define FW_SLV_ID_GPIO2_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 114)
+#define FW_SLV_ID_GPIO2_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 115)
+#define FW_SLV_ID_GPIO3_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 116)
+#define FW_SLV_ID_GPIO3_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 117)
+#define FW_SLV_ID_GPIO3_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 118)
+#define FW_SLV_ID_GPIO3_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 119)
+#define FW_SLV_ID_GPIO4_CH0		FW_SLV_ID(FW_SLV_TYPE_BUS, 120)
+#define FW_SLV_ID_GPIO4_CH1		FW_SLV_ID(FW_SLV_TYPE_BUS, 121)
+#define FW_SLV_ID_GPIO4_CH2		FW_SLV_ID(FW_SLV_TYPE_BUS, 122)
+#define FW_SLV_ID_GPIO4_CH3		FW_SLV_ID(FW_SLV_TYPE_BUS, 123)
+#define FW_SLV_ID_BUS_CNT		125
+
+#define FW_SLV_ID_ACDCDIG_DSM		FW_SLV_ID(FW_SLV_TYPE_TOP, 0)
+#define FW_SLV_ID_ASRC2CH_0		FW_SLV_ID(FW_SLV_TYPE_TOP, 1)
+#define FW_SLV_ID_ASRC2CH_1		FW_SLV_ID(FW_SLV_TYPE_TOP, 2)
+#define FW_SLV_ID_ASRC4CH_0		FW_SLV_ID(FW_SLV_TYPE_TOP, 3)
+#define FW_SLV_ID_ASRC4CH_1		FW_SLV_ID(FW_SLV_TYPE_TOP, 4)
+#define FW_SLV_ID_PDM1			FW_SLV_ID(FW_SLV_TYPE_TOP, 5)
+#define FW_SLV_ID_SAI0_8CH		FW_SLV_ID(FW_SLV_TYPE_TOP, 6)
+#define FW_SLV_ID_SAI1_8CH		FW_SLV_ID(FW_SLV_TYPE_TOP, 7)
+#define FW_SLV_ID_SAI2_8CH		FW_SLV_ID(FW_SLV_TYPE_TOP, 8)
+#define FW_SLV_ID_SAI3_2CH		FW_SLV_ID(FW_SLV_TYPE_TOP, 9)
+#define FW_SLV_ID_SAI4_2CH		FW_SLV_ID(FW_SLV_TYPE_TOP, 10)
+#define FW_SLV_ID_SPDIF_RX0		FW_SLV_ID(FW_SLV_TYPE_TOP, 11)
+#define FW_SLV_ID_SPDIF_RX1		FW_SLV_ID(FW_SLV_TYPE_TOP, 12)
+#define FW_SLV_ID_SPDIF_TX0		FW_SLV_ID(FW_SLV_TYPE_TOP, 13)
+#define FW_SLV_ID_SPDIF_TX1		FW_SLV_ID(FW_SLV_TYPE_TOP, 14)
+#define FW_SLV_ID_DSMC_MEM		FW_SLV_ID(FW_SLV_TYPE_TOP, 15)
+#define FW_SLV_ID_FSPI1			FW_SLV_ID(FW_SLV_TYPE_TOP, 16)
+#define FW_SLV_ID_FLEXBUS		FW_SLV_ID(FW_SLV_TYPE_TOP, 17)
+#define FW_SLV_ID_SDIO			FW_SLV_ID(FW_SLV_TYPE_TOP, 18)
+#define FW_SLV_ID_SDMMC			FW_SLV_ID(FW_SLV_TYPE_TOP, 19)
+#define FW_SLV_ID_DSMC_CFG		FW_SLV_ID(FW_SLV_TYPE_TOP, 20)
+#define FW_SLV_ID_GMAC0			FW_SLV_ID(FW_SLV_TYPE_TOP, 21)
+#define FW_SLV_ID_GMAC1			FW_SLV_ID(FW_SLV_TYPE_TOP, 22)
+#define FW_SLV_ID_SDGMAC_GRF		FW_SLV_ID(FW_SLV_TYPE_TOP, 23)
+#define FW_SLV_ID_EMMC			FW_SLV_ID(FW_SLV_TYPE_TOP, 24)
+#define FW_SLV_ID_FSPI0			FW_SLV_ID(FW_SLV_TYPE_TOP, 25)
+#define FW_SLV_ID_NSCRYPTO		FW_SLV_ID(FW_SLV_TYPE_TOP, 26)
+#define FW_SLV_ID_RKRNG_NS		FW_SLV_ID(FW_SLV_TYPE_TOP, 27)
+#define FW_SLV_ID_SCRYPTO		FW_SLV_ID(FW_SLV_TYPE_TOP, 28)
+#define FW_SLV_ID_KEYLAD		FW_SLV_ID(FW_SLV_TYPE_TOP, 29)
+#define FW_SLV_ID_RKRNG_S		FW_SLV_ID(FW_SLV_TYPE_TOP, 30)
+#define FW_SLV_ID_OTPC_NS		FW_SLV_ID(FW_SLV_TYPE_TOP, 31)
+#define FW_SLV_ID_JTAG_LOCK		FW_SLV_ID(FW_SLV_TYPE_TOP, 33)
+#define FW_SLV_ID_OTPC_S		FW_SLV_ID(FW_SLV_TYPE_TOP, 34)
+#define FW_SLV_ID_OTPMASK		FW_SLV_ID(FW_SLV_TYPE_TOP, 35)
+#define FW_SLV_ID_SECURE_CRU		FW_SLV_ID(FW_SLV_TYPE_TOP, 36)
+#define FW_SLV_ID_SECURE_CRU_S		FW_SLV_ID(FW_SLV_TYPE_TOP, 37)
+#define FW_SLV_ID_SYS_SGRF		FW_SLV_ID(FW_SLV_TYPE_TOP, 38)
+#define FW_SLV_ID_BOOTROM		FW_SLV_ID(FW_SLV_TYPE_TOP, 39)
+#define FW_SLV_ID_WDT_S			FW_SLV_ID(FW_SLV_TYPE_TOP, 41)
+#define FW_SLV_ID_SERVICE_GMAC		FW_SLV_ID(FW_SLV_TYPE_TOP, 42)
+#define FW_SLV_ID_SERVICE_NVM		FW_SLV_ID(FW_SLV_TYPE_TOP, 43)
+#define FW_SLV_ID_SERVICE_SECURE	FW_SLV_ID(FW_SLV_TYPE_TOP, 44)
+#define FW_SLV_ID_SERVICE_VENC		FW_SLV_ID(FW_SLV_TYPE_TOP, 45)
+#define FW_SLV_ID_SERVICE_VI		FW_SLV_ID(FW_SLV_TYPE_TOP, 46)
+#define FW_SLV_ID_SERVICE_VPU		FW_SLV_ID(FW_SLV_TYPE_TOP, 47)
+#define FW_SLV_ID_VEPU0			FW_SLV_ID(FW_SLV_TYPE_TOP, 48)
+#define FW_SLV_ID_ISP			FW_SLV_ID(FW_SLV_TYPE_TOP, 49)
+#define FW_SLV_ID_VICAP			FW_SLV_ID(FW_SLV_TYPE_TOP, 50)
+#define FW_SLV_ID_VPSS			FW_SLV_ID(FW_SLV_TYPE_TOP, 51)
+#define FW_SLV_ID_CSIHOST0		FW_SLV_ID(FW_SLV_TYPE_TOP, 52)
+#define FW_SLV_ID_CSIHOST1		FW_SLV_ID(FW_SLV_TYPE_TOP, 53)
+#define FW_SLV_ID_CSIHOST2		FW_SLV_ID(FW_SLV_TYPE_TOP, 54)
+#define FW_SLV_ID_VI_GRF		FW_SLV_ID(FW_SLV_TYPE_TOP, 55)
+#define FW_SLV_ID_EBC			FW_SLV_ID(FW_SLV_TYPE_TOP, 56)
+#define FW_SLV_ID_JPEG			FW_SLV_ID(FW_SLV_TYPE_TOP, 57)
+#define FW_SLV_ID_RGA0			FW_SLV_ID(FW_SLV_TYPE_TOP, 58)
+#define FW_SLV_ID_RGA1			FW_SLV_ID(FW_SLV_TYPE_TOP, 59)
+#define FW_SLV_ID_VDPP			FW_SLV_ID(FW_SLV_TYPE_TOP, 60)
+#define FW_SLV_ID_TIMER_S_0_CH0		FW_SLV_ID(FW_SLV_TYPE_TOP, 61)
+#define FW_SLV_ID_TIMER_S_0_CH1		FW_SLV_ID(FW_SLV_TYPE_TOP, 62)
+#define FW_SLV_ID_TIMER_S_0_CH2		FW_SLV_ID(FW_SLV_TYPE_TOP, 63)
+#define FW_SLV_ID_TIMER_S_0_CH3		FW_SLV_ID(FW_SLV_TYPE_TOP, 64)
+#define FW_SLV_ID_TIMER_S_0_CH4		FW_SLV_ID(FW_SLV_TYPE_TOP, 65)
+#define FW_SLV_ID_TIMER_S_0_CH5		FW_SLV_ID(FW_SLV_TYPE_TOP, 66)
+#define FW_SLV_ID_TIMER_S_1_CH0		FW_SLV_ID(FW_SLV_TYPE_TOP, 67)
+#define FW_SLV_ID_TIMER_S_1_CH1		FW_SLV_ID(FW_SLV_TYPE_TOP, 68)
+#define FW_SLV_ID_TIMER_S_1_CH2		FW_SLV_ID(FW_SLV_TYPE_TOP, 69)
+#define FW_SLV_ID_TIMER_S_1_CH3		FW_SLV_ID(FW_SLV_TYPE_TOP, 70)
+#define FW_SLV_ID_TIMER_S_1_CH4		FW_SLV_ID(FW_SLV_TYPE_TOP, 71)
+#define FW_SLV_ID_TIMER_S_1_CH5		FW_SLV_ID(FW_SLV_TYPE_TOP, 72)
+#define FW_SLV_ID_SYS_FW		FW_SLV_ID(FW_SLV_TYPE_TOP, 73)
+#define FW_SLV_ID_VEPU1			FW_SLV_ID(FW_SLV_TYPE_TOP, 75)
+#define FW_SLV_ID_SERVICE_VEPU1		FW_SLV_ID(FW_SLV_TYPE_TOP, 76)
+#define FW_SLV_ID_CSIHOST3		FW_SLV_ID(FW_SLV_TYPE_TOP, 77)
+#define FW_SLV_ID_CSIHOST4		FW_SLV_ID(FW_SLV_TYPE_TOP, 78)
+#define FW_SLV_ID_TOP_CNT		80
+
+#define FW_SLV_ID_CENTER_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 0)
+#define FW_SLV_ID_DMA2DDR		FW_SLV_ID(FW_SLV_TYPE_CENTER, 1)
+#define FW_SLV_ID_AHB2APB		FW_SLV_ID(FW_SLV_TYPE_CENTER, 2)
+#define FW_SLV_ID_DDR_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 3)
+#define FW_SLV_ID_DDRCTL0		FW_SLV_ID(FW_SLV_TYPE_CENTER, 4)
+#define FW_SLV_ID_DDRCTL_1		FW_SLV_ID(FW_SLV_TYPE_CENTER, 5)
+#define FW_SLV_ID_DDRPHY0		FW_SLV_ID(FW_SLV_TYPE_CENTER, 6)
+#define FW_SLV_ID_DDR0_CRU		FW_SLV_ID(FW_SLV_TYPE_CENTER, 7)
+#define FW_SLV_ID_DDRPHY1		FW_SLV_ID(FW_SLV_TYPE_CENTER, 8)
+#define FW_SLV_ID_DDR1_CRU		FW_SLV_ID(FW_SLV_TYPE_CENTER, 9)
+#define FW_SLV_ID_DDRMON0		FW_SLV_ID(FW_SLV_TYPE_CENTER, 10)
+#define FW_SLV_ID_DDRMON1		FW_SLV_ID(FW_SLV_TYPE_CENTER, 11)
+#define FW_SLV_ID_HWLP0			FW_SLV_ID(FW_SLV_TYPE_CENTER, 12)
+#define FW_SLV_ID_HWLP1			FW_SLV_ID(FW_SLV_TYPE_CENTER, 13)
+#define FW_SLV_ID_DDR_PVTPLL		FW_SLV_ID(FW_SLV_TYPE_CENTER, 14)
+#define FW_SLV_ID_DDR_WDT		FW_SLV_ID(FW_SLV_TYPE_CENTER, 15)
+#define FW_SLV_ID_RKVDEC		FW_SLV_ID(FW_SLV_TYPE_CENTER, 16)
+#define FW_SLV_ID_SERVICE_CCI2		FW_SLV_ID(FW_SLV_TYPE_CENTER, 17)
+#define FW_SLV_ID_SERVICE_CENTER	FW_SLV_ID(FW_SLV_TYPE_CENTER, 18)
+#define FW_SLV_ID_SERVICE_DDR		FW_SLV_ID(FW_SLV_TYPE_CENTER, 19)
+#define FW_SLV_ID_SERVICE_RKVDEC	FW_SLV_ID(FW_SLV_TYPE_CENTER, 20)
+#define FW_SLV_ID_SERVICE_USB		FW_SLV_ID(FW_SLV_TYPE_CENTER, 21)
+#define FW_SLV_ID_SERVICE_VO0		FW_SLV_ID(FW_SLV_TYPE_CENTER, 22)
+#define FW_SLV_ID_SERVICE_VO1		FW_SLV_ID(FW_SLV_TYPE_CENTER, 23)
+#define FW_SLV_ID_SERVICE_VOP		FW_SLV_ID(FW_SLV_TYPE_CENTER, 24)
+#define FW_SLV_ID_UFS_APBS		FW_SLV_ID(FW_SLV_TYPE_CENTER, 25)
+#define FW_SLV_ID_UFS_AXIS		FW_SLV_ID(FW_SLV_TYPE_CENTER, 26)
+#define FW_SLV_ID_USB0			FW_SLV_ID(FW_SLV_TYPE_CENTER, 27)
+#define FW_SLV_ID_MMU2			FW_SLV_ID(FW_SLV_TYPE_CENTER, 28)
+#define FW_SLV_ID_USB_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 29)
+#define FW_SLV_ID_HDCP0_MMU		FW_SLV_ID(FW_SLV_TYPE_CENTER, 30)
+#define FW_SLV_ID_SAI5_8CH		FW_SLV_ID(FW_SLV_TYPE_CENTER, 31)
+#define FW_SLV_ID_SAI6_8CH		FW_SLV_ID(FW_SLV_TYPE_CENTER, 32)
+#define FW_SLV_ID_SPDIF_RX2		FW_SLV_ID(FW_SLV_TYPE_CENTER, 33)
+#define FW_SLV_ID_SPDIF_TX2		FW_SLV_ID(FW_SLV_TYPE_CENTER, 34)
+#define FW_SLV_ID_HDCP0_KEY		FW_SLV_ID(FW_SLV_TYPE_CENTER, 35)
+#define FW_SLV_ID_DSIHOST		FW_SLV_ID(FW_SLV_TYPE_CENTER, 36)
+#define FW_SLV_ID_EDP0			FW_SLV_ID(FW_SLV_TYPE_CENTER, 37)
+#define FW_SLV_ID_HDCP0			FW_SLV_ID(FW_SLV_TYPE_CENTER, 38)
+#define FW_SLV_ID_HDCP0_TRNG		FW_SLV_ID(FW_SLV_TYPE_CENTER, 39)
+#define FW_SLV_ID_HDMITX		FW_SLV_ID(FW_SLV_TYPE_CENTER, 40)
+#define FW_SLV_ID_VO0_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 41)
+#define FW_SLV_ID_EDP0_S		FW_SLV_ID(FW_SLV_TYPE_CENTER, 42)
+#define FW_SLV_ID_HDCP1_MMU		FW_SLV_ID(FW_SLV_TYPE_CENTER, 43)
+#define FW_SLV_ID_SAI7_8CH		FW_SLV_ID(FW_SLV_TYPE_CENTER, 44)
+#define FW_SLV_ID_SPDIF_TX3		FW_SLV_ID(FW_SLV_TYPE_CENTER, 45)
+#define FW_SLV_ID_HDCP1_KEY		FW_SLV_ID(FW_SLV_TYPE_CENTER, 46)
+#define FW_SLV_ID_DP			FW_SLV_ID(FW_SLV_TYPE_CENTER, 47)
+#define FW_SLV_ID_HDCP1			FW_SLV_ID(FW_SLV_TYPE_CENTER, 48)
+#define FW_SLV_ID_HDCP1_TRNG		FW_SLV_ID(FW_SLV_TYPE_CENTER, 49)
+#define FW_SLV_ID_VO1_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 50)
+#define FW_SLV_ID_VOP_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 52)
+#define FW_SLV_ID_UFS_GRF		FW_SLV_ID(FW_SLV_TYPE_CENTER, 53)
+#define FW_SLV_ID_SPDIF_TX4		FW_SLV_ID(FW_SLV_TYPE_CENTER, 54)
+#define FW_SLV_ID_SPDIF_TX5		FW_SLV_ID(FW_SLV_TYPE_CENTER, 55)
+#define FW_SLV_ID_SAI8_8CH		FW_SLV_ID(FW_SLV_TYPE_CENTER, 56)
+#define FW_SLV_ID_SAI9_8CH		FW_SLV_ID(FW_SLV_TYPE_CENTER, 57)
+#define FW_SLV_ID_DDR_TIMER_CH0		FW_SLV_ID(FW_SLV_TYPE_CENTER, 58)
+#define FW_SLV_ID_DDR_TIMER_CH1		FW_SLV_ID(FW_SLV_TYPE_CENTER, 59)
+#define FW_SLV_ID_VOP_RGN0		FW_SLV_ID(FW_SLV_TYPE_CENTER, 60)
+#define FW_SLV_ID_VOP_RGN1		FW_SLV_ID(FW_SLV_TYPE_CENTER, 61)
+#define FW_SLV_ID_VOP_RGN2		FW_SLV_ID(FW_SLV_TYPE_CENTER, 62)
+#define FW_SLV_ID_VOP_RGN3		FW_SLV_ID(FW_SLV_TYPE_CENTER, 63)
+#define FW_SLV_ID_VOP_OTHERS		FW_SLV_ID(FW_SLV_TYPE_CENTER, 64)
+#define FW_SLV_ID_CENTER_CNT		65
+
+#define FW_SLV_ID_BIGCORE_CRU		FW_SLV_ID(FW_SLV_TYPE_CCI, 0)
+#define FW_SLV_ID_BIGCORE_GRF		FW_SLV_ID(FW_SLV_TYPE_CCI, 1)
+#define FW_SLV_ID_CCI			FW_SLV_ID(FW_SLV_TYPE_CCI, 2)
+#define FW_SLV_ID_CCI_CRU		FW_SLV_ID(FW_SLV_TYPE_CCI, 3)
+#define FW_SLV_ID_CCI_PVTPLL		FW_SLV_ID(FW_SLV_TYPE_CCI, 4)
+#define FW_SLV_ID_CCI_GRF		FW_SLV_ID(FW_SLV_TYPE_CCI, 5)
+#define FW_SLV_ID_DAP_LITE_A53		FW_SLV_ID(FW_SLV_TYPE_CCI, 6)
+#define FW_SLV_ID_DAP_LITE_A72		FW_SLV_ID(FW_SLV_TYPE_CCI, 7)
+#define FW_SLV_ID_LITCORE_GRF		FW_SLV_ID(FW_SLV_TYPE_CCI, 8)
+#define FW_SLV_ID_LITCORE_CRU		FW_SLV_ID(FW_SLV_TYPE_CCI, 9)
+#define FW_SLV_ID_SERVICE_CCI		FW_SLV_ID(FW_SLV_TYPE_CCI, 10)
+#define FW_SLV_ID_BIGCORE_PVTPLL	FW_SLV_ID(FW_SLV_TYPE_CCI, 11)
+#define FW_SLV_ID_LITCORE_PVTPLL	FW_SLV_ID(FW_SLV_TYPE_CCI, 12)
+#define FW_SLV_ID_CCI_CNT		15
+
+#define FW_SLV_ID_PCIE0_DBI		FW_SLV_ID(FW_SLV_TYPE_PHP, 0)
+#define FW_SLV_ID_PCIE0_DBI_L		FW_SLV_ID(FW_SLV_TYPE_PHP, 1)
+#define FW_SLV_ID_PCIE0_S		FW_SLV_ID(FW_SLV_TYPE_PHP, 2)
+#define FW_SLV_ID_PCIE0_S_L		FW_SLV_ID(FW_SLV_TYPE_PHP, 3)
+#define FW_SLV_ID_PCIE1_DBI		FW_SLV_ID(FW_SLV_TYPE_PHP, 4)
+#define FW_SLV_ID_PCIE1_DBI_L		FW_SLV_ID(FW_SLV_TYPE_PHP, 5)
+#define FW_SLV_ID_PCIE1_S		FW_SLV_ID(FW_SLV_TYPE_PHP, 6)
+#define FW_SLV_ID_PCIE1_S_L		FW_SLV_ID(FW_SLV_TYPE_PHP, 7)
+#define FW_SLV_ID_USB1			FW_SLV_ID(FW_SLV_TYPE_PHP, 8)
+#define FW_SLV_ID_PCIE0_APB		FW_SLV_ID(FW_SLV_TYPE_PHP, 9)
+#define FW_SLV_ID_PCIE1_APB		FW_SLV_ID(FW_SLV_TYPE_PHP, 10)
+#define FW_SLV_ID_PHP_GRF		FW_SLV_ID(FW_SLV_TYPE_PHP, 11)
+#define FW_SLV_ID_SATA0			FW_SLV_ID(FW_SLV_TYPE_PHP, 12)
+#define FW_SLV_ID_SATA1			FW_SLV_ID(FW_SLV_TYPE_PHP, 13)
+#define FW_SLV_ID_SERVICE_PHP		FW_SLV_ID(FW_SLV_TYPE_PHP, 14)
+#define FW_SLV_ID_MMU0			FW_SLV_ID(FW_SLV_TYPE_PHP, 15)
+#define FW_SLV_ID_MMU1			FW_SLV_ID(FW_SLV_TYPE_PHP, 16)
+#define FW_SLV_ID_PHP_CNT		20
+
+#define FW_SLV_ID_GPU_GRF		FW_SLV_ID(FW_SLV_TYPE_GPU, 0)
+#define FW_SLV_ID_GPU			FW_SLV_ID(FW_SLV_TYPE_GPU, 1)
+#define FW_SLV_ID_SERVICE_GPU		FW_SLV_ID(FW_SLV_TYPE_GPU, 2)
+#define FW_SLV_ID_GPU_PVTPLL		FW_SLV_ID(FW_SLV_TYPE_GPU, 3)
+#define FW_SLV_ID_GPU_CNT		5
+
+#define FW_SLV_ID_RKNN_TOP		FW_SLV_ID(FW_SLV_TYPE_NPU, 0)
+#define FW_SLV_ID_SERVICE_NPU0		FW_SLV_ID(FW_SLV_TYPE_NPU, 1)
+#define FW_SLV_ID_SERVICE_NPU1		FW_SLV_ID(FW_SLV_TYPE_NPU, 2)
+#define FW_SLV_ID_SERVICE_NPUSUBSYS	FW_SLV_ID(FW_SLV_TYPE_NPU, 3)
+#define FW_SLV_ID_RKNN_NSP		FW_SLV_ID(FW_SLV_TYPE_NPU, 4)
+#define FW_SLV_ID_NPU_GRF		FW_SLV_ID(FW_SLV_TYPE_NPU, 5)
+#define FW_SLV_ID_NPU_PVTPLL		FW_SLV_ID(FW_SLV_TYPE_NPU, 6)
+#define FW_SLV_ID_NPU_WDT		FW_SLV_ID(FW_SLV_TYPE_NPU, 7)
+#define FW_SLV_ID_NPU_TIMER_CH0		FW_SLV_ID(FW_SLV_TYPE_NPU, 8)
+#define FW_SLV_ID_NPU_TIMER_CH1		FW_SLV_ID(FW_SLV_TYPE_NPU, 9)
+#define FW_SLV_ID_NPU_CNT		10
+
+#define FW_SLV_ID_PDM0			FW_SLV_ID(FW_SLV_TYPE_PMU, 0)
+#define FW_SLV_ID_PMU_MEM		FW_SLV_ID(FW_SLV_TYPE_PMU, 1)
+#define FW_SLV_ID_CSIDPHY_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 2)
+#define FW_SLV_ID_VDMA			FW_SLV_ID(FW_SLV_TYPE_PMU, 3)
+#define FW_SLV_ID_HDPTXPHY		FW_SLV_ID(FW_SLV_TYPE_PMU, 4)
+#define FW_SLV_ID_HDPTXPHY0_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 5)
+#define FW_SLV_ID_I2C0			FW_SLV_ID(FW_SLV_TYPE_PMU, 6)
+#define FW_SLV_ID_DCPHY			FW_SLV_ID(FW_SLV_TYPE_PMU, 7)
+#define FW_SLV_ID_CSIDPHY0		FW_SLV_ID(FW_SLV_TYPE_PMU, 8)
+#define FW_SLV_ID_DCPHY_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 9)
+#define FW_SLV_ID_PMU0			FW_SLV_ID(FW_SLV_TYPE_PMU, 10)
+#define FW_SLV_ID_PMU0_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 11)
+#define FW_SLV_ID_PMU0_IOC		FW_SLV_ID(FW_SLV_TYPE_PMU, 12)
+#define FW_SLV_ID_PMU1			FW_SLV_ID(FW_SLV_TYPE_PMU, 13)
+#define FW_SLV_ID_PMU1_CRU		FW_SLV_ID(FW_SLV_TYPE_PMU, 14)
+#define FW_SLV_ID_PMU1_CRU_S		FW_SLV_ID(FW_SLV_TYPE_PMU, 15)
+#define FW_SLV_ID_PMU1_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 16)
+#define FW_SLV_ID_PMU1_IOC		FW_SLV_ID(FW_SLV_TYPE_PMU, 17)
+#define FW_SLV_ID_PWM0_CH0		FW_SLV_ID(FW_SLV_TYPE_PMU, 18)
+#define FW_SLV_ID_PWM0_CH1		FW_SLV_ID(FW_SLV_TYPE_PMU, 19)
+#define FW_SLV_ID_UART1			FW_SLV_ID(FW_SLV_TYPE_PMU, 20)
+#define FW_SLV_ID_MPHY_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 21)
+#define FW_SLV_ID_MPHY			FW_SLV_ID(FW_SLV_TYPE_PMU, 22)
+#define FW_SLV_ID_USB2PHY0_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 23)
+#define FW_SLV_ID_USB2PHY1_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 24)
+#define FW_SLV_ID_USBDPPHY		FW_SLV_ID(FW_SLV_TYPE_PMU, 25)
+#define FW_SLV_ID_USBDPPHY_GRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 26)
+#define FW_SLV_ID_VCCIO6_IOC		FW_SLV_ID(FW_SLV_TYPE_PMU, 27)
+#define FW_SLV_ID_PMU_WDT		FW_SLV_ID(FW_SLV_TYPE_PMU, 28)
+#define FW_SLV_ID_HPTIMER		FW_SLV_ID(FW_SLV_TYPE_PMU, 29)
+#define FW_SLV_ID_OSC_CHK		FW_SLV_ID(FW_SLV_TYPE_PMU, 30)
+#define FW_SLV_ID_PMU0_SGRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 31)
+#define FW_SLV_ID_PMU1_SGRF		FW_SLV_ID(FW_SLV_TYPE_PMU, 32)
+#define FW_SLV_ID_PMU_PVTM		FW_SLV_ID(FW_SLV_TYPE_PMU, 33)
+#define FW_SLV_ID_SCRAMBLE_KEY		FW_SLV_ID(FW_SLV_TYPE_PMU, 34)
+#define FW_SLV_ID_SERVICE_PMU		FW_SLV_ID(FW_SLV_TYPE_PMU, 35)
+#define FW_SLV_ID_PMU_SRAM_REMAP	FW_SLV_ID(FW_SLV_TYPE_PMU, 36)
+#define FW_SLV_ID_PMU_TIMER_CH0		FW_SLV_ID(FW_SLV_TYPE_PMU, 37)
+#define FW_SLV_ID_PMU_TIMER_CH1		FW_SLV_ID(FW_SLV_TYPE_PMU, 38)
+#define FW_SLV_ID_GPIO0_CH0		FW_SLV_ID(FW_SLV_TYPE_PMU, 39)
+#define FW_SLV_ID_GPIO0_CH1		FW_SLV_ID(FW_SLV_TYPE_PMU, 40)
+#define FW_SLV_ID_GPIO0_CH2		FW_SLV_ID(FW_SLV_TYPE_PMU, 41)
+#define FW_SLV_ID_GPIO0_CH3		FW_SLV_ID(FW_SLV_TYPE_PMU, 42)
+#define FW_SLV_ID_PMU_FW		FW_SLV_ID(FW_SLV_TYPE_PMU, 43)
+#define FW_SLV_ID_PMU_CNT		45
+
+#define PLAT_MAX_DDR_CAPACITY_MB	0x8000	/* for 32Gb */
+#define RG_MAP_SECURE(top, base)	\
+	(((((top) - 1) & 0x7fff) << 16) | ((base) & 0x7fff))
+#define RG_MAP_SRAM_SECURE(top_kb, base_kb)	\
+	(((((top_kb) / 4 - 1) & 0xff) << 8) | ((base_kb) / 4 & 0xff))
+#define RG_MAP_CBUF_SECURE(top_kb, base_kb)	\
+	(((((top_kb) / 4 - 1) & 0xff) << 8) | ((base_kb) / 4 & 0xff))
+
+#define FW_UPDATE_WAIT_LOOP		500000
+
+__pmusramfunc void pmusram_fw_update_msk(uint32_t msk);
+__pmusramfunc void pmusram_all_fw_bypass(void);
+
+void fw_init(void);
+
+#endif /* __FIREWALL_H__ */
diff --git a/plat/rockchip/rk3576/drivers/secure/secure.c b/plat/rockchip/rk3576/drivers/secure/secure.c
new file mode 100644
index 0000000..55b8d93
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/secure/secure.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+#include <secure.h>
+#include <soc.h>
+
+static void secure_timer_init(void)
+{
+	/* gpu's cntvalue comes from stimer1 channel_5 */
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
+		      TIMER_DIS);
+
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_LOAD_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_LOAD_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
+		      TIMER_EN | TIMER_FMODE);
+}
+
+void secure_init(void)
+{
+	secure_timer_init();
+	fw_init();
+
+	/* crypto secure controlled by crypto */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), BITS_WITH_WMASK(0, 0x1, 4));
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), BITS_WITH_WMASK(0, 0x1, 5));
+
+	/* disable DP encryption mode */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(1), BITS_WITH_WMASK(1, 0x1, 14));
+}
diff --git a/plat/rockchip/rk3576/drivers/secure/secure.h b/plat/rockchip/rk3576/drivers/secure/secure.h
new file mode 100644
index 0000000..f00e519
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/secure/secure.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+#include <firewall.h>
+
+/* PMU0SGRF */
+#define PMU0SGRF_SOC_CON(i)		((i) * 4)
+
+ /* PMU1SGRF */
+#define PMU1SGRF_SOC_CON(i)		((i) * 4)
+
+  /* CCISGRF */
+#define CCISGRF_SOC_CON(i)		(0x20 + (i) * 4)
+#define CCISGRF_DDR_HASH_CON(i)		(0x40 + (i) * 4)
+
+ /* SGRF */
+#define SYSSGRF_DDR_BANK_MSK(i)		(0x04 + (i) * 4)
+#define SYSSGRF_DDR_CH_MSK(i)		(0x18 + (i) * 4)
+#define SYSSGRF_SOC_CON(i)		(0x20 + (i) * 4)
+#define SYSSGRF_DMAC_CON(i)		(0x80 + (i) * 4)
+#define SYSSGRF_SOC_STATUS		0x240
+
+void secure_init(void);
+
+#endif /* SECURE_H */
diff --git a/plat/rockchip/rk3576/drivers/soc/soc.c b/plat/rockchip/rk3576/drivers/soc/soc.c
new file mode 100644
index 0000000..a78e82e
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/soc/soc.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <pmu.h>
+
+#include <plat_private.h>
+#include <rk3576_clk.h>
+#include <secure.h>
+#include <soc.h>
+
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(RK3576_DEV_RNG0_BASE, RK3576_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_SHARE_MEM, DDR_SHARE_SIZE,
+			MT_DEVICE | MT_RW | MT_NS),
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	/* No of children for the second cluster node */
+	PLATFORM_CLUSTER1_CORE_COUNT
+};
+
+static void clear_glb_reset_status(void)
+{
+	uint32_t cru_sel55 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(55));
+
+	/* switch pclk_bus_root to 24M before writing CRU_GLB_RST_ST */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(55),
+		      BITS_WITH_WMASK(2, 0x3, 2));
+	dsb();
+
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_ST, 0xffff);
+	dsb();
+
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(55),
+		      WITH_16BITS_WMSK(cru_sel55));
+}
+
+static void print_glb_reset_status(void)
+{
+	uint32_t glb_rst_st = 0, warm_boot = 0;
+
+	/* clear CRU_GLB_RST_ST_NCLR if cold boot */
+	if (mmio_read_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(17)) == WARM_BOOT_MAGIC) {
+		/* ignore npu_wdt*/
+		glb_rst_st = mmio_read_32(CRU_BASE + CRU_GLB_RST_ST_NCLR) & VALID_GLB_RST_MSK;
+		warm_boot = 1;
+	} else {
+		mmio_write_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(17), WARM_BOOT_MAGIC);
+	}
+
+	clear_glb_reset_status();
+
+	/* save glb_rst_st in mem_os_reg31 */
+	write_mem_os_reg(31, glb_rst_st);
+
+	if (warm_boot != 0)
+		INFO("soc warm boot, reset status: 0x%x\n", glb_rst_st);
+	else
+		INFO("soc cold boot\n");
+}
+
+static void system_reset_init(void)
+{
+	/*
+	 * enable tsadc trigger global reset and select first reset.
+	 * enable global reset and wdt trigger pmu reset.
+	 * select first reset trigger pmu reset.
+	 */
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, 0xffdf);
+
+	/* enable wdt_s reset */
+	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0), 0x20002000);
+
+	/* enable wdt_ns reset */
+	mmio_write_32(SYS_GRF_BASE + SYSGRF_SOC_CON(4), 0x01000100);
+
+	/* reset width = 0xffff */
+	mmio_write_32(PMU1_GRF_BASE + PMU1GRF_SOC_CON(6), 0xffffffff);
+
+	/* enable first/tsadc/wdt reset output */
+	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070007);
+
+	/* pmu0sgrf pmu0_ioc hold */
+	mmio_write_32(PMU0SGRF_BASE + PMU1SGRF_SOC_CON(0), 0xffff1800);
+
+	/* pmu1sgrf pmu1_grf hold */
+	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(16), 0xffff8800);
+
+	/* select tsadc_shut_m0 ionmux*/
+	mmio_write_32(PMU0_IOC_BASE + 0x0, 0x00f00090);
+
+	print_glb_reset_status();
+}
+
+void plat_rockchip_soc_init(void)
+{
+	rockchip_clock_init();
+	system_reset_init();
+	secure_init();
+	rockchip_init_scmi_server();
+
+	/* release cpu1~cpu7 */
+	mmio_write_32(CCI_GRF_BASE + CCIGRF_CON(4), 0xffffffff);
+	mmio_write_32(LITCORE_GRF_BASE + COREGRF_CPU_CON(1),
+		      BITS_WITH_WMASK(0x77, 0xff, 4));
+}
diff --git a/plat/rockchip/rk3576/drivers/soc/soc.h b/plat/rockchip/rk3576/drivers/soc/soc.h
new file mode 100644
index 0000000..f96a42d
--- /dev/null
+++ b/plat/rockchip/rk3576/drivers/soc/soc.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __SOC_H__
+#define __SOC_H__
+
+enum pll_id {
+	APLL_ID,
+	CPLL_ID,
+	DPLL_ID,
+	GPLL_ID,
+};
+
+enum cru_mode_con00 {
+	CLK_APLL,
+	CLK_CPLL,
+	CLK_GPLL,
+	CLK_DPLL,
+};
+
+#define KHz				1000
+#define MHz				(1000 * KHz)
+#define OSC_HZ				(24 * MHz)
+
+#define MCU_VALID_START_ADDRESS		0x800000
+
+/* CRU */
+#define GLB_SRST_FST_CFG_VAL		0xfdb9
+
+#define CRU_PLLS_CON(pll_id, i)		((pll_id) * 0x20 + (i) * 0x4)
+#define CRU_PLL_CON(i)			((i) * 0x4)
+#define CRU_MODE_CON			0x280
+#define CRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define CRU_CLKSEL_CON_CNT		181
+#define CRU_CLKGATE_CON(i)		((i) * 0x4 + 0x800)
+#define CRU_CLKGATE_CON_CNT		80
+#define CRU_SOFTRST_CON(i)		((i) * 0x4 + 0xa00)
+#define CRU_SOFTRST_CON_CNT		80
+
+#define CRU_GLB_CNT_TH			0xc00
+#define CRU_GLB_RST_ST			0xc04
+#define CRU_GLB_SRST_FST		0xc08
+#define CRU_GLB_SRST_SND		0xc0c
+#define CRU_GLB_RST_CON			0xc10
+#define CRU_GLB_RST_ST_NCLR		0xc14
+#define CRU_LITCOREWFI_CON0		0xc40
+#define CRU_BIGCOREWFI_CON0		0xc44
+#define CRU_NON_SECURE_GT_CON0		0xc48
+
+#define CRU_PLLCON0_M_MASK		0x3ff
+#define CRU_PLLCON0_M_SHIFT		0
+#define CRU_PLLCON1_P_MASK		0x3f
+#define CRU_PLLCON1_P_SHIFT		0
+#define CRU_PLLCON1_S_MASK		0x7
+#define CRU_PLLCON1_S_SHIFT		6
+#define CRU_PLLCON2_K_MASK		0xffff
+#define CRU_PLLCON2_K_SHIFT		0
+#define CRU_PLLCON1_PWRDOWN		BIT(13)
+#define CRU_PLLCON6_LOCK_STATUS		BIT(15)
+
+/* LCORE_CRU */
+#define LCORE_CRU_MODE_CON		0x280
+#define LCORE_CRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define LCORE_CRU_CLKSEL_CON_CNT	4
+#define LCORE_CRU_CLKGATE_CON(i)	((i) * 0x4 + 0x800)
+#define LCORE_CRU_CLKGATE_CON_CNT	2
+#define LCORE_CRU_SOFTRST_CON(i)	((i) * 0x4 + 0xa00)
+#define LCORE_CRU_SOFTRST_CON_CNT	4
+
+/* BCORE_CRU */
+#define BCORE_CRU_MODE_CON		0x280
+#define BCORE_CRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define BCORE_CRU_CLKSEL_CON_CNT	5
+#define BCORE_CRU_CLKGATE_CON(i)	((i) * 0x4 + 0x800)
+#define BCORE_CRU_CLKGATE_CON_CNT	3
+#define BCORE_CRU_SOFTRST_CON(i)	((i) * 0x4 + 0xa00)
+#define BCORE_CRU_SOFTRST_CON_CNT	4
+
+/* DDRCRU */
+#define DDRCRU_MODE_CON			0x280
+#define DDRCRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define DDRCRU_CLKGATE_CON(i)		((i) * 0x4 + 0x800)
+#define DDRCRU_SOFTRST_CON(i)		((i) * 0x4 + 0xa00)
+
+/* CCICRU */
+#define CCICRU_MODE_CON			0x280
+#define CCICRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define CCICRU_CLKSEL_CON_CNT		10
+#define CCICRU_CLKGATE_CON(i)		((i) * 0x4 + 0x800)
+#define CCICRU_CLKGATE_CON_CNT		7
+#define CCICRU_SOFTRST_CON(i)		((i) * 0x4 + 0xa00)
+#define CCICRU_SOFTRST_CON_CNT		7
+
+/* CRU AUTOCS */
+#define CRU_AUTOCS_CON(offset)		(CRU_BASE + (offset))
+#define CRU_AUTOCS_SEC_CON(offset)	(SECURE_CRU_BASE + (offset))
+#define CRU_AUTOCS_CCI_CON(offset)	(CCI_CRU_BASE + (offset))
+#define AUTOCS_EN_BIT			BIT(12)
+
+/* PHP_CRU */
+#define PHP_CRU_MODE_CON		0x280
+#define PHP_CRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
+#define PHP_CRU_CLKSEL_CON_CNT		2
+#define PHP_CRU_CLKGATE_CON(i)		((i) * 0x4 + 0x800)
+#define PHP_CRU_CLKGATE_CON_CNT		2
+#define PHP_CRU_SOFTRST_CON(i)		((i) * 0x4 + 0xa00)
+#define PHP_CRU_SOFTRST_CON_CNT		2
+
+/* SECURE CRU */
+#define SECURE_CRU_CLKSEL_CON(i)	((i) * 0x4 + 0x300)
+#define SECURE_CRU_CLKSEL_CON_CNT	1
+#define SECURE_CRU_CLKGATE_CON(i)	((i) * 0x4 + 0x800)
+#define SECURE_CRU_CLKGATE_CON_CNT	1
+#define SECURE_CRU_SOFTRST_CON(i)	((i) * 0x4 + 0xa00)
+#define SECURE_CRU_SOFTRST_CON_CNT	1
+
+/* SECURE SCRU */
+#define SECURE_SCRU_CLKSEL_CON(i)	((i) * 0x4 + 0x4000)
+#define SECURE_SCRU_CLKSEL_CON_CNT	7
+#define SECURE_SCRU_CLKGATE_CON(i)	((i) * 0x4 + 0x4028)
+#define SECURE_SCRU_CLKGATE_CON_CNT	6
+#define SECURE_SCRU_SOFTRST_CON(i)	((i) * 0x4 + 0x4050)
+#define SECURE_SCRU_SOFTRST_CON_CNT	6
+#define SECURE_SCRU_MODE_CON		0x4280
+
+/* SYSGRF */
+#define SYSGRF_SOC_CON(i)		((i) * 4)
+#define SYSGRF_SOC_STATUS		0x30
+#define SYSGRF_NOC_CON(i)		(0x40 + (i) * 4)
+#define SYSGRF_NOC_STATUS(i)		(0x60 + (i) * 4)
+#define SYSGRF_MEM_CON(i)		(0x80 + (i) * 4)
+#define SYSGRF_STATUS0			0x140
+#define SYSGRF_STATUS1			0x144
+
+/* COREGRF */
+#define COREGRF_SOC_STATUS(i)		(0x2c + (i) * 4)
+#define COREGRF_CPU_CON(i)		(0x34 + (i) * 4)
+
+/* DDRGRF */
+#define DDRGRF_CHA_CON(i)		((i) * 4)
+#define DDRGRF_CHB_CON(i)		(0x100 + (i) * 4)
+#define DDRGRF_CHA_ST(i)		(0x60 + (i) * 4)
+#define DDRGRF_CHB_ST(i)		(0xb0 + (i) * 4)
+#define DDRGRF_CON(i)			(0x140 + (i) * 4)
+
+/* CCIGRF */
+#define CCIGRF_CON(i)			((i) * 4)
+#define CCIGRF_STATUS(i)		(0x34 + (i) * 4)
+
+/* IOC */
+#define VCCIO_IOC_MISC_CON(i)		(0x400 + (i) * 4)
+
+/* pvtm */
+#define PVTM_CON(i)			(0x4 + (i) * 4)
+#define PVTM_INTEN			0x70
+#define PVTM_INTSTS			0x74
+#define PVTM_STATUS(i)			(0x80 + (i) * 4)
+#define PVTM_CALC_CNT			0x200
+
+enum pvtm_con0 {
+	pvtm_start = 0,
+	pvtm_osc_en = 1,
+	pvtm_osc_sel = 2,
+	pvtm_rnd_seed_en = 5,
+};
+
+/* WDT */
+#define WDT_CR			0x0
+#define WDT_TORR		0x4
+#define WDT_CCVR		0x8
+#define WDT_CRR			0xc
+#define WDT_STAT		0x10
+#define WDT_EOI			0x14
+
+#define WDT_EN			BIT(0)
+#define WDT_RSP_MODE		BIT(1)
+
+/* timer */
+#define TIMER_LOAD_COUNT0		0x00
+#define TIMER_LOAD_COUNT1		0x04
+#define TIMER_CURRENT_VALUE0		0x08
+#define TIMER_CURRENT_VALUE1		0x0c
+#define TIMER_CONTROL_REG		0x10
+#define TIMER_INTSTATUS			0x18
+
+#define TIMER_DIS			0x0
+#define TIMER_EN			0x1
+
+#define TIMER_FMODE			(0x0 << 1)
+#define TIMER_RMODE			(0x1 << 1)
+
+/* hp timer */
+#define TIMER_HP_REVISION		0x00
+#define TIMER_HP_CTRL			0x04
+#define TIMER_HP_INTR_EN		0x08
+#define TIMER_HP_T24_GCD		0x0c
+#define TIMER_HP_T32_GCD		0x10
+#define TIMER_HP_LOAD_COUNT0		0x14
+#define TIMER_HP_LOAD_COUNT1		0x18
+#define TIMER_HP_T24_DELAT_COUNT0	0x1c
+#define TIMER_HP_T24_DELAT_COUNT1	0x20
+#define TIMER_HP_CURR_32K_VALUE0	0x24
+#define TIMER_HP_CURR_32K_VALUE1	0x28
+#define TIMER_HP_CURR_TIMER_VALUE0	0x2c
+#define TIMER_HP_CURR_TIMER_VALUE1	0x30
+#define TIMER_HP_T24_32BEGIN0		0x34
+#define TIMER_HP_T24_32BEGIN1		0x38
+#define TIMER_HP_T32_24END0		0x3c
+#define TIMER_HP_T32_24END1		0x40
+#define TIMER_HP_BEGIN_END_VALID	0x44
+#define TIMER_HP_SYNC_REQ		0x48
+#define TIMER_HP_INTR_STATUS		0x4c
+#define TIMER_HP_UPD_EN			0x50
+
+ /* GPIO */
+#define GPIO_SWPORT_DR_L		0x0000
+#define GPIO_SWPORT_DR_H		0x0004
+#define GPIO_SWPORT_DDR_L		0x0008
+#define GPIO_SWPORT_DDR_H		0x000c
+#define GPIO_INT_EN_L			0x0010
+#define GPIO_INT_EN_H			0x0014
+#define GPIO_INT_MASK_L			0x0018
+#define GPIO_INT_MASK_H			0x001c
+#define GPIO_INT_TYPE_L			0x0020
+#define GPIO_INT_TYPE_H			0x0024
+#define GPIO_INT_POLARITY_L		0x0028
+#define GPIO_INT_POLARITY_H		0x002c
+#define GPIO_INT_BOTHEDGE_L		0x0030
+#define GPIO_INT_BOTHEDGE_H		0x0034
+#define GPIO_DEBOUNCE_L			0x0038
+#define GPIO_DEBOUNCE_H			0x003c
+#define GPIO_DBCLK_DIV_EN_L		0x0040
+#define GPIO_DBCLK_DIV_EN_H		0x0044
+#define GPIO_DBCLK_DIV_CON		0x0048
+#define GPIO_INT_STATUS			0x0050
+#define GPIO_INT_RAWSTATUS		0x0058
+#define GPIO_PORT_EOI_L			0x0060
+#define GPIO_PORT_EOI_H			0x0064
+#define GPIO_EXT_PORT			0x0070
+#define GPIO_VER_ID			0x0078
+#define GPIO_STORE_ST_L			0x0080
+#define GPIO_STORE_ST_H			0x0084
+#define GPIO_REG_GROUP_L		0x0100
+#define GPIO_REG_GROUP_H		0x0104
+#define GPIO_VIRTUAL_EN			0x0108
+#define GPIO_REG_GROUP1_L		0x0110
+#define GPIO_REG_GROUP1_H		0x0114
+#define GPIO_REG_GROUP2_L		0x0118
+#define GPIO_REG_GROUP2_H		0x011c
+#define GPIO_REG_GROUP3_L		0x0120
+#define GPIO_REG_GROUP3_H		0x0124
+
+/* PWM */
+#define PMW_PWRCAPTURE_VAL		0x15c
+
+#define SOC_RK3576A1			0x35760101
+#define SOC_RK3576J1			0x35760a01
+#define SOC_RK3576M1			0x35760d01
+#define SOC_RK3576S1			0x35761301
+#define SOC_UNKNOWN			0xeeee
+#define SOC_ROOT			0x0
+
+int rk_soc_is_(uint32_t soc_id);
+uint32_t timer_hp_get_freq(void);
+int soc_bus_div_sip_handler(uint32_t id, uint32_t cfg, uint32_t enable_msk);
+void autocs_suspend(void);
+void autocs_resume(void);
+
+#endif /* __SOC_H__ */
diff --git a/plat/rockchip/rk3576/include/plat.ld.S b/plat/rockchip/rk3576/include/plat.ld.S
new file mode 100644
index 0000000..4d0096f
--- /dev/null
+++ b/plat/rockchip/rk3576/include/plat.ld.S
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef ROCKCHIP_PLAT_LD_S
+#define ROCKCHIP_PLAT_LD_S
+
+MEMORY {
+	PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		KEEP(*(.pmusram.entry))
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		. = ALIGN(PAGE_SIZE);
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		. = ALIGN(PAGE_SIZE);
+		__bl31_pmusram_data_end = .;
+
+		ASSERT(__bl31_pmusram_data_end <= PMUSRAM_BASE + PMUSRAM_RSIZE,
+			".pmusram has exceeded its limit.");
+	} >PMUSRAM
+}
+#endif /* ROCKCHIP_PLAT_LD_S */
diff --git a/plat/rockchip/rk3576/include/plat_sip_calls.h b/plat/rockchip/rk3576/include/plat_sip_calls.h
new file mode 100644
index 0000000..c33f24f
--- /dev/null
+++ b/plat/rockchip/rk3576/include/plat_sip_calls.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __PLAT_SIP_CALLS_H__
+#define __PLAT_SIP_CALLS_H__
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* __PLAT_SIP_CALLS_H__ */
diff --git a/plat/rockchip/rk3576/include/platform_def.h b/plat/rockchip/rk3576/include/platform_def.h
new file mode 100644
index 0000000..03a80b0
--- /dev/null
+++ b/plat/rockchip/rk3576/include/platform_def.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include <common_def.h>
+#include <rk3576_def.h>
+
+#define DEBUG_XLAT_TABLE 0
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if DEBUG_XLAT_TABLE
+#define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL1
+#define PLATFORM_STACK_SIZE 0x440
+#elif IMAGE_BL2
+#define PLATFORM_STACK_SIZE 0x400
+#elif IMAGE_BL31
+#define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL32
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	6
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		1
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		2
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF txet, ro, rw, Size: 512KB */
+#define TZRAM_BASE		RK_DRAM_BASE
+#define TZRAM_SIZE		0x100000
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted RAM
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x40000)
+#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+
+#define ADDR_SPACE_SIZE			(1ULL << 32)
+#define MAX_XLAT_TABLES			18
+#define MAX_MMAP_REGIONS		27
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE	PLAT_GICD_BASE
+#define PLAT_RK_GICC_BASE	PLAT_GICC_BASE
+#define PLAT_RK_GICR_BASE	PLAT_GICR_BASE
+
+#define PLAT_RK_UART_BASE	RK_DBG_UART_BASE
+#define PLAT_RK_UART_CLOCK	RK_DBG_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE	RK_DBG_UART_BAUDRATE
+
+#define PLAT_RK_PRIMARY_CPU	0x0
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rockchip/rk3576/plat_sip_calls.c b/plat/rockchip/rk3576/plat_sip_calls.c
new file mode 100644
index 0000000..b0ff5fb
--- /dev/null
+++ b/plat/rockchip/rk3576/plat_sip_calls.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/scmi-msg.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+				    u_register_t x1,
+				    u_register_t x2,
+				    u_register_t x3,
+				    u_register_t x4,
+				    void *cookie,
+				    void *handle,
+				    u_register_t flags)
+{
+	switch (smc_fid) {
+	case RK_SIP_SCMI_AGENT0:
+		scmi_smt_fastcall_smc_entry(0);
+		SMC_RET1(handle, 0);
+
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/rockchip/rk3576/platform.mk b/plat/rockchip/rk3576/platform.mk
new file mode 100644
index 0000000..861cb4f
--- /dev/null
+++ b/plat/rockchip/rk3576/platform.mk
@@ -0,0 +1,115 @@
+#
+# Copyright (c) 2025, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RK_PLAT			:=	plat/rockchip
+RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON		:=	${RK_PLAT}/common
+
+DISABLE_BIN_GENERATION	:=	1
+
+include drivers/arm/gic/v2/gicv2.mk
+include lib/libfdt/libfdt.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES		:=	-Idrivers/arm/gic/common/			\
+				-Idrivers/arm/gic/v2/				\
+				-Idrivers/scmi-msg/				\
+				-Iinclude/bl31					\
+				-Iinclude/common				\
+				-Iinclude/drivers				\
+				-Iinclude/drivers/arm				\
+				-Iinclude/drivers/io				\
+				-Iinclude/drivers/ti/uart			\
+				-Iinclude/lib					\
+				-Iinclude/lib/cpus/${ARCH}			\
+				-Iinclude/lib/el3_runtime			\
+				-Iinclude/lib/psci				\
+				-Iinclude/plat/common				\
+				-Iinclude/services				\
+				-I${RK_PLAT_COMMON}/				\
+				-I${RK_PLAT_COMMON}/pmusram/			\
+				-I${RK_PLAT_COMMON}/include/			\
+				-I${RK_PLAT_COMMON}/drivers/pmu/		\
+				-I${RK_PLAT_COMMON}/drivers/parameter/		\
+				-I${RK_PLAT_COMMON}/scmi/			\
+				-I${RK_PLAT_SOC}/				\
+				-I${RK_PLAT_SOC}/drivers/dmc/			\
+				-I${RK_PLAT_SOC}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/drivers/secure/		\
+				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/include/			\
+				-I${RK_PLAT_SOC}/scmi/
+
+RK_GIC_SOURCES		:=	${GICV2_SOURCES}				\
+				plat/common/plat_gicv2.c			\
+				${RK_PLAT}/common/rockchip_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	${XLAT_TABLES_LIB_SRCS}				\
+				common/desc_image_load.c			\
+				lib/bl_aux_params/bl_aux_params.c		\
+				plat/common/aarch64/crash_console_helpers.S	\
+				plat/common/plat_psci_common.c
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES	+=	${RK_PLAT_COMMON}/rockchip_stack_protector.c
+endif
+
+BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
+				drivers/arm/cci/cci.c				\
+				drivers/ti/uart/aarch64/16550_console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/scmi-msg/base.c				\
+				drivers/scmi-msg/clock.c			\
+				drivers/scmi-msg/entry.c			\
+				drivers/scmi-msg/reset_domain.c			\
+				drivers/scmi-msg/smt.c				\
+				lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a72.S			\
+				$(LIBFDT_SRCS)					\
+				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
+				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
+				${RK_PLAT_COMMON}/plat_pm.c			\
+				${RK_PLAT_COMMON}/plat_pm_helpers.c		\
+				${RK_PLAT_COMMON}/plat_topology.c		\
+				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+				${RK_PLAT_COMMON}/params_setup.c		\
+				${RK_PLAT_COMMON}/pmusram/cpus_on_fixed_addr.S	\
+				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+				${RK_PLAT_COMMON}/scmi/rockchip_common_clock.c	\
+				${RK_PLAT_COMMON}/scmi/scmi.c			\
+				${RK_PLAT_COMMON}/scmi/scmi_clock.c		\
+				${RK_PLAT_COMMON}/scmi/scmi_rstd.c		\
+				${RK_PLAT_SOC}/scmi/rk3576_clk.c		\
+				${RK_PLAT_SOC}/plat_sip_calls.c         	\
+				${RK_PLAT_SOC}/drivers/dmc/suspend.c		\
+				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+				${RK_PLAT_SOC}/drivers/pmu/pm_pd_regs.c 	\
+				${RK_PLAT_SOC}/drivers/secure/firewall.c	\
+				${RK_PLAT_SOC}/drivers/secure/secure.c		\
+				${RK_PLAT_SOC}/drivers/soc/soc.c
+
+# Enable workarounds for selected Cortex-A53 errata
+ERRATA_A53_835769		:=	1
+ERRATA_A53_843419		:=	1
+ERRATA_A53_855873		:=	1
+ERRATA_A53_1530924		:=	1
+
+ERRATA_A72_1319367		:=	1
+
+ENABLE_PLAT_COMPAT		:=	0
+MULTI_CONSOLE_API		:=	1
+CTX_INCLUDE_EL2_REGS		:=	0
+GICV2_G0_FOR_EL3		:=	1
+CTX_INCLUDE_AARCH32_REGS	:=	0
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS		:=	0
+
+WORKAROUND_CVE_2017_5715	:=	0
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
diff --git a/plat/rockchip/rk3576/rk3576_def.h b/plat/rockchip/rk3576/rk3576_def.h
new file mode 100644
index 0000000..35f38ca
--- /dev/null
+++ b/plat/rockchip/rk3576/rk3576_def.h
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __PLAT_DEF_H__
+#define __PLAT_DEF_H__
+
+#define SIZE_K(n)		((n) * 1024)
+#define SIZE_M(n)		((n) * 1024 * 1024)
+
+#define WITH_16BITS_WMSK(bits)	(0xffff0000 | (bits))
+#define BITS_WMSK(msk, shift)	((msk) << ((shift) + REG_MSK_SHIFT))
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define RK3576_DEV_RNG0_BASE	0x00000000
+#define RK3576_DEV_RNG0_SIZE	0x40000000
+
+#define RK_DRAM_BASE		0x40000000
+
+/* All slave base address declare below */
+#define MCU_TCM_BASE		0x23800000
+#define MCU_CACHE_BASE		0x23810000
+#define MCU_RAM_TEST_BASE	0x23820000
+#define MCU_BOOT_BASE		0x00000000
+#define MCU_MAIN_BASE		0x00010000
+#define PMU0SGRF_BASE		0x26000000
+#define PMU1SGRF_BASE		0x26002000
+#define PMU1SGRF_FW_BASE	0x26003000
+#define SYS_SGRF_BASE		0x26004000
+#define SYS_SGRF_FW_BASE	0x26005000
+#define SYS_GRF_BASE		0x2600a000
+#define BIGCORE_GRF_BASE	0x2600c000
+#define LITCORE_GRF_BASE	0x2600e000
+#define CCI_GRF_BASE		0x26010000
+#define DDR_GRF_BASE		0x26012000
+#define CENTER_GRF_BASE		0x26014000
+#define GPUGRF_BASE		0x26016000
+#define NPUGRF_BASE		0x26018000
+#define VO_GRF_BASE		0x2601a000
+#define VI_GRF_BASE		0x2601c000
+#define USB_GRF_BASE		0x2601e000
+#define PHP_GRF_BASE		0x26020000
+#define VOP_GRF_BASE		0x26022000
+#define PMU0_GRF_BASE		0x26024000
+#define PMU1_GRF_BASE		0x26026000
+#define USBDPPHY_GRF_BASE	0x2602c000
+#define USB2PHY0_GRF_BASE	0x2602e000
+#define USB2PHY1_GRF_BASE	0x26030000
+#define PMU0_IOC_BASE		0x26040000
+#define PMU1_IOC_BASE		0x26042000
+#define TOP_IOC_BASE		0x26044000
+#define VCCIO_IOC_BASE		0x26046000
+#define VCCIO6_IOC_BASE		0x2604a000
+#define VCCIO7_IOC_BASE		0x2604b000
+#define CRU_BASE		0x27200000
+#define PHP_CRU_BASE		0x27208000
+#define SECURE_CRU_BASE		0x27210000
+#define PMU1_CRU_BASE		0x27220000
+#define DDRPHY0_CRU_BASE	0x27228000
+#define DDRPHY1_CRU_BASE	0x27230000
+#define BIGCORE_CRU_BASE	0x27238000
+#define LITTLE_CRU_BASE		0x27240000
+#define CCI_CRU_BASE		0x27248000
+#define PVTPLL_CCI_BASE		0x27250000
+#define PVTPLL_BIGCORE_BASE	0x27258000
+#define PVTPLL_LITCORE_BASE	0x27260000
+#define PVTPLL_GPU_BASE		0x27268000
+#define PVTPLL_NPU_BASE		0x27270000
+#define PVTPLL_CRU_BASE		0x27278000
+#define I2C0_BASE		0x27300000
+#define UART1_BASE		0x27310000
+#define GPIO0_BASE		0x27320000
+#define PWM0_BASE		0x27330000
+#define WDT_PMU_BASE		0x27340000
+#define TIMER_PMU_BASE		0x27350000
+#define PMU_BASE		0x27360000
+#define PMU0_BASE		0x27360000
+#define PMU1_BASE		0x27370000
+#define PMU2_BASE		0x27380000
+#define PVTM_PMU_BASE		0x273f0000
+#define HPTIMER_BASE		0x27400000
+#define CCI_BASE		0x27500000
+#define VOP_BASE		0x27d00000
+#define INTERCONNECT_BASE	0x27f00000
+#define FW_CCI2DDR_BASE		0x27f80000
+#define FW_CENTER2DDR_BASE	0x27f90000
+#define FW_SYSMEM_BASE		0x27fa0000
+#define FW_VOP2DDR_BASE		0x27fb0000
+#define FW_CBUF_BASE		0x27fc0000
+#define FIREWALL_DDR_BASE	0x27f80000
+#define DDRCTL0_BASE		0x28000000
+#define DDRCTL1_BASE		0x29000000
+#define DDR_MONITOR0_BASE	0x2a000000
+#define DDR_MONITOR1_BASE	0x2a010000
+#define DDRPHY0_BASE		0x2a020000
+#define DDRPHY1_BASE		0x2a030000
+#define HWLP0_BASE		0x2a060000
+#define HWLP1_BASE		0x2a070000
+#define KEYLADDER_BASE		0x2a420000
+#define CRYPTO_S_BASE		0x2a430000
+#define OTP_S_BASE		0x2a480000
+#define DCF_BASE		0x2a490000
+#define STIMER0_BASE		0x2a4a0000
+#define STIMER1_BASE		0x2a4b0000
+#define WDT_S_BASE		0x2a4c0000
+#define OTP_MASK_BASE		0x2a4d0000
+#define OTP_NS_BASE		0x2a580000
+#define GIC400_BASE		0x2a700000
+#define I2C1_BASE		0x2ac40000
+#define NSTIMER0_BASE		0x2acc0000
+#define NSTIMER1_BASE		0x2acd0000
+#define WDT_NS_BASE		0x2ace0000
+#define UART0_BASE		0x2ad40000
+#define UART2_BASE		0x2ad50000
+#define UART3_BASE		0x2ad60000
+#define UART4_BASE		0x2ad70000
+#define UART5_BASE		0x2ad80000
+#define UART6_BASE		0x2ad90000
+#define UART7_BASE		0x2ada0000
+#define UART8_BASE		0x2adb0000
+#define UART9_BASE		0x2adc0000
+#define PWM1_BASE		0x2add0000
+#define PWM2_BASE		0x2ade0000
+#define PWM3_BASE		0x2adf0000
+#define GPIO1_BASE		0x2ae10000
+#define GPIO2_BASE		0x2ae20000
+#define GPIO3_BASE		0x2ae30000
+#define GPIO4_BASE		0x2ae40000
+#define TSADC_BASE		0x2ae70000
+
+#define PMUSRAM_BASE		0x3fe70000
+#define PMUSRAM_RSIZE		SIZE_K(32)
+
+#define CBUF_BASE		0x3fe80000
+#define SRAM_BASE		0x3ff80000
+
+#define STIMER0_CHN_BASE(i)	(STIMER0_BASE + 0x1000 * (i))
+#define STIMER1_CHN_BASE(i)	(STIMER1_BASE + 0x1000 * (i))
+
+#define NSTIMER0_CHN_BASE(i)	(NSTIMER0_BASE + 0x1000 * (i))
+#define NSTIMER1_CHN_BASE(i)	(NSTIMER1_BASE + 0x1000 * (i))
+
+#define DDRPHY_BASE_CH(n)	(DDRPHY0_BASE + ((n) * 0x10000))
+#define DDRPHY_CRU_BASE_CH(n)	(DDRPHY0_CRU_BASE + ((n) * 0x8000))
+#define UMCTL_BASE_CH(n)	(DDRCTL0_BASE + ((n) * 0x1000000))
+#define HWLP_BASE_CH(n)		(HWLP0_BASE + ((n) * 0x10000))
+#define MAILBOX1_BASE		(0x2ae50000 + 0xb000)
+
+#define CRYPTO_S_BY_KEYLAD_BASE	CRYPTO_S_BASE
+
+#define DDR_SHARE_MEM		(RK_DRAM_BASE + SIZE_K(1024))
+#define DDR_SHARE_SIZE		SIZE_K(64)
+
+#define SHARE_MEM_BASE		DDR_SHARE_MEM
+#define SHARE_MEM_PAGE_NUM	15
+#define SHARE_MEM_SIZE		SIZE_K(SHARE_MEM_PAGE_NUM * 4)
+
+#define	SCMI_SHARE_MEM_BASE	(SHARE_MEM_BASE + SHARE_MEM_SIZE)
+#define	SCMI_SHARE_MEM_SIZE	SIZE_K(4)
+
+#define SMT_BUFFER_BASE		SCMI_SHARE_MEM_BASE
+#define SMT_BUFFER0_BASE	SMT_BUFFER_BASE
+
+#define ROCKCHIP_PM_REG_REGION_MEM_SIZE		SIZE_K(8)
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define RK_IRQ_SEC_PHY_TIMER	29
+
+#define RK_IRQ_SEC_SGI_0	8
+#define RK_IRQ_SEC_SGI_1	9
+#define RK_IRQ_SEC_SGI_2	10
+#define RK_IRQ_SEC_SGI_3	11
+#define RK_IRQ_SEC_SGI_4	12
+#define RK_IRQ_SEC_SGI_5	13
+#define RK_IRQ_SEC_SGI_6	14
+#define RK_IRQ_SEC_SGI_7	15
+
+/*
+ * Define a list of Group 0 interrupts.
+ */
+#define PLAT_RK_GICV2_G0_IRQS						\
+	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),		\
+	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+/* UART related constants */
+#define RK_DBG_UART_BASE	UART0_BASE
+#define RK_DBG_UART_BAUDRATE	1500000
+#define RK_DBG_UART_CLOCK	24000000
+
+/* Base rk_platform compatible GIC memory map */
+#define PLAT_GICD_BASE		(GIC400_BASE + 0x1000)
+#define PLAT_GICC_BASE		(GIC400_BASE + 0x2000)
+#define PLAT_GICR_BASE		0
+
+/* CCI */
+#define PLAT_RK_CCI_BASE			CCI_BASE
+#define PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX	1
+#define PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX	2
+
+#endif /* __PLAT_DEF_H__ */
diff --git a/plat/rockchip/rk3576/scmi/rk3576_clk.c b/plat/rockchip/rk3576/scmi/rk3576_clk.c
new file mode 100644
index 0000000..7b36a05
--- /dev/null
+++ b/plat/rockchip/rk3576/scmi/rk3576_clk.c
@@ -0,0 +1,1353 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <drivers/delay_timer.h>
+#include <drivers/scmi.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <platform_def.h>
+
+#include <plat_private.h>
+#include <rk3576_clk.h>
+#include <rockchip_sip_svc.h>
+#include <scmi_clock.h>
+#include <soc.h>
+
+enum pll_type_sel {
+	PLL_SEL_AUTO, /* all plls (normal pll or pvtpll) */
+	PLL_SEL_PVT,
+	PLL_SEL_NOR,
+	PLL_SEL_AUTO_NOR /* all normal plls (apll/gpll/npll) */
+};
+
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+#define RK3576_PVTPLL_RING_EN		0x00
+#define RK3576_PVTPLL_RING0_LENGTH	0x04
+#define RK3576_PVTPLL_RING1_LENGTH	0x08
+#define RK3576_PVTPLL_RING2_LENGTH	0x0c
+#define RK3576_PVTPLL_RING3_LENGTH	0x10
+#define RK3576_PVTPLL_GCK_CFG		0x20
+#define RK3576_PVTPLL_GCK_LEN		0x24
+#define RK3576_PVTPLL_GCK_DIV		0x28
+#define RK3576_PVTPLL_GCK_CAL_CNT	0x2c
+#define RK3576_PVTPLL_GCK_REF_VAL	0x30
+#define RK3576_PVTPLL_GCK_CFG_VAL	0x34
+#define RK3576_PVTPLL_GCK_THR		0x38
+#define RK3576_PVTPLL_GFREE_CON		0x3c
+#define RK3576_PVTPLL_ADC_CFG		0x40
+#define RK3576_PVTPLL_ADC_CAL_CNT	0x48
+#define RK3576_PVTPLL_GCK_CNT		0x50
+#define RK3576_PVTPLL_GCK_CNT_AVG	0x54
+#define RK3576_PVTPLL_GCK_STATE		0x5c
+#define RK3576_PVTPLL_ADC_CNT		0x60
+#define RK3576_PVTPLL_ADC_CNT_AVG	0x68
+#define RK3576_PVTPLL_VERSION		0x70
+#define RK3576_PVTPLL_MAX_LENGTH	0x3f
+
+#define GPLL_RATE			1188000000
+#define CPLL_RATE			1000000000
+#define SPLL_RATE			702000000
+#define AUPLL_RATE			786431952
+
+#define MAX_RATE_TABLE			16
+
+#define CLKDIV_6BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x3fU, shift)
+#define CLKDIV_5BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x1fU, shift)
+#define CLKDIV_4BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0xfU, shift)
+#define CLKDIV_3BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x7U, shift)
+#define CLKDIV_2BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x3U, shift)
+#define CLKDIV_1BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x1U, shift)
+
+#define CPU_PLL_PATH_SLOWMODE		BITS_WITH_WMASK(0U, 0x3U, 0)
+#define CPU_PLL_PATH_NORMAL		BITS_WITH_WMASK(1U, 0x3U, 0)
+#define CPU_PLL_PATH_DEEP_SLOW		BITS_WITH_WMASK(2U, 0x3U, 0)
+
+#define CRU_PLL_POWER_DOWN		BIT_WITH_WMSK(13)
+#define CRU_PLL_POWER_UP		WMSK_BIT(13)
+
+/* clk_core:
+ * from normal pll(core_i: gpll or apll) path or direct pass from apll
+ */
+
+/* cpul clk path */
+#define CPUL_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(1U, 0x3U, 12)
+#define CPUL_CLK_PATH_NOR_LPLL		BITS_WITH_WMASK(0U, 0x3U, 12)
+#define CPUL_CLK_PATH_NOR_PVTPLL	BITS_WITH_WMASK(2U, 0x3U, 12)
+
+#define CPUL_CLK_PATH_LPLL		BITS_WITH_WMASK(0U, 0x3U, 6)
+#define CPUL_CLK_PATH_DIR_LPLL		BITS_WITH_WMASK(2U, 0x3U, 6)
+#define CPUL_CLK_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x3U, 6)
+
+#define CPUL_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 13)
+#define CPUL_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(0x1, 0x1U, 13)
+
+/* cpub clk path */
+#define CPUB_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(1U, 0x3U, 12)
+#define CPUB_CLK_PATH_NOR_BPLL		BITS_WITH_WMASK(0U, 0x3U, 12)
+#define CPUB_CLK_PATH_NOR_PVTPLL	BITS_WITH_WMASK(2U, 0x3U, 12)
+
+#define CPUB_CLK_PATH_BPLL		BITS_WITH_WMASK(0U, 0x3U, 14)
+#define CPUB_CLK_PATH_DIR_BPLL		BITS_WITH_WMASK(2U, 0x3U, 14)
+#define CPUB_CLK_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x3U, 14)
+
+#define CPUB_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 5)
+#define CPUB_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(0x1, 0x1U, 5)
+
+#define CPUB_PCLK_PATH_100M		BITS_WITH_WMASK(0U, 0x3U, 0)
+#define CPUB_PCLK_PATH_50M		BITS_WITH_WMASK(1U, 0x3U, 0)
+#define CPUB_PCLK_PATH_24M		BITS_WITH_WMASK(2U, 0x3U, 0)
+
+/* cci clk path */
+#define SCLK_CCI_PATH_XIN		BITS_WITH_WMASK(0U, 0x3U, 12)
+#define SCLK_CCI_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x3U, 12)
+#define SCLK_CCI_PATH_NOR_LPLL		BITS_WITH_WMASK(3U, 0x3U, 12)
+#define SCLK_CCI_PATH_NOR_GPLL		BITS_WITH_WMASK(2U, 0x3U, 12)
+
+#define CCI_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 14)
+#define CCI_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x1U, 14)
+
+/* npu clk path */
+#define NPU_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(0U, 0x7U, 7)
+#define NPU_CLK_PATH_NOR_CPLL		BITS_WITH_WMASK(1U, 0x7U, 7)
+#define NPU_CLK_PATH_NOR_AUPLL		BITS_WITH_WMASK(2U, 0x7U, 7)
+#define NPU_CLK_PATH_NOR_SPLL		BITS_WITH_WMASK(3U, 0x7U, 7)
+
+#define NPU_CLK_PATH_NOR_PLL		WMSK_BIT(15)
+#define NPU_CLK_PATH_PVTPLL		BIT_WITH_WMSK(15)
+#define NPU_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 9)
+#define NPU_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x1U, 9)
+
+/* gpu clk path */
+#define GPU_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(0U, 0x7U, 5)
+#define GPU_CLK_PATH_NOR_CPLL		BITS_WITH_WMASK(1U, 0x7U, 5)
+#define GPU_CLK_PATH_NOR_AUPLL		BITS_WITH_WMASK(2U, 0x7U, 5)
+#define GPU_CLK_PATH_NOR_SPLL		BITS_WITH_WMASK(3U, 0x7U, 5)
+#define GPU_CLK_PATH_NOR_LPLL		BITS_WITH_WMASK(4U, 0x7U, 5)
+#define GPU_CLK_PATH_NOR_PLL		WMSK_BIT(8)
+#define GPU_CLK_PATH_PVTPLL		BIT_WITH_WMSK(8)
+#define GPU_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 9)
+#define GPU_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x1U, 9)
+
+#define PVTPLL_NEED(type, length)	(((type) == PLL_SEL_PVT || \
+					  (type) == PLL_SEL_AUTO) && \
+					 (length))
+/*
+ * [0]:      set intermediate rate
+ *           [1]: scaling up rate or scaling down rate
+ * [1]:      add length for pvtpll
+ *           [2:5]: length
+ * [2]:      use low length for pvtpll
+ * [3:5]:    reserved
+ */
+#define OPP_RATE_MASK			0x3f
+#define OPP_INTERMEDIATE_RATE		BIT(0)
+#define OPP_SCALING_UP_RATE		BIT(1)
+#define OPP_ADD_LENGTH			BIT(1)
+#define OPP_LENGTH_MASK			GENMASK_32(5, 2)
+#define OPP_LENGTH_SHIFT		2
+#define OPP_LENGTH_LOW			BIT(2)
+
+#define PRATE(x) static const unsigned long const x[]
+#define PINFO(x) static const uint32_t const x[]
+
+PRATE(p_24m)			= { OSC_HZ };
+PRATE(p_100m_24m)		= { 100 * MHz, OSC_HZ };
+PRATE(p_350m_175m_116m_24m)	= { 350 * MHz, 175 * MHz, 116 * MHz, OSC_HZ };
+PRATE(p_175m_116m_58m_24m)	= { 175 * MHz, 116 * MHz, 58 * MHz, OSC_HZ };
+PRATE(p_116m_58m_24m)		= { 116 * MHz, 58 * MHz, OSC_HZ };
+PRATE(p_pclk_secure_s)		= { PCLK_SECURE_S };
+PRATE(p_hclk_secure_s)		= { HCLK_SECURE_S };
+PRATE(p_aclk_secure_s)		= { ACLK_SECURE_S };
+PRATE(p_hclk_vo0_s)		= { HCLK_VO0_S };
+PRATE(p_pclk_vo0_s)		= { PCLK_VO0_S };
+PRATE(p_hclk_vo1_s)		= { HCLK_VO1_S };
+PRATE(p_pclk_vo1_s)		= { PCLK_VO1_S };
+
+PINFO(clk_stimer0_root_info)	= { 0x27214004, 6, 1, 0, 0, 0, 0x27214028, 9 };
+PINFO(clk_stimer1_root_info)	= { 0x27214004, 7, 1, 0, 0, 0, 0x2721402c, 1 };
+PINFO(pclk_secure_s_info)	= { 0x27214004, 4, 2, 0, 0, 0, 0x27214028, 2 };
+PINFO(hclk_secure_s_info)	= { 0x27214004, 2, 2, 0, 0, 0, 0x27214028, 1 };
+PINFO(aclk_secure_s_info)	= { 0x27214004, 0, 2, 0, 0, 0, 0x27214028, 0 };
+PINFO(clk_pka_crypto_s_info)	= { 0x27214004, 11, 2, 0, 0, 0, 0x27214030, 11 };
+PINFO(hclk_vo1_s_info)		= { 0x27214010, 0, 2, 0, 0, 0, 0x27214038, 1 };
+PINFO(pclk_vo1_s_info)		= { 0x27214010, 2, 2, 0, 0, 0, 0x27214038, 4 };
+PINFO(hclk_vo0_s_info)		= { 0x27214018, 0, 2, 0, 0, 0, 0x2721403c, 1 };
+PINFO(pclk_vo0_s_info)		= { 0x27214018, 2, 2, 0, 0, 0, 0x2721403c, 4 };
+PINFO(pclk_klad_info)		= { 0, 0, 0, 0, 0, 0, 0x27214030, 7 };
+PINFO(hclk_crypto_s_info)	= { 0, 0, 0, 0, 0, 0, 0x27214030, 8 };
+PINFO(hclk_klad_info)		= { 0, 0, 0, 0, 0, 0, 0x27214030, 9 };
+PINFO(aclk_crypto_s_info)	= { 0, 0, 0, 0, 0, 0, 0x27214030, 12 };
+PINFO(hclk_trng_s_info)		= { 0, 0, 0, 0, 0, 0, 0x27214034, 0 };
+PINFO(pclk_otpc_s_info)		= { 0, 0, 0, 0, 0, 0, 0x27214034, 3 };
+PINFO(clk_otpc_s_info)		= { 0, 0, 0, 0, 0, 0, 0x27214034, 4 };
+PINFO(pclk_wdt_s_info)		= { 0, 0, 0, 0, 0, 0, 0x27214034, 9 };
+PINFO(tclk_wdt_s_info)		= { 0, 0, 0, 0, 0, 0, 0x27214034, 10 };
+PINFO(pclk_hdcp1_trng_info)	= { 0, 0, 0, 0, 0, 0, 0x27214038, 0 };
+PINFO(hclk_hdcp_key1_info)	= { 0, 0, 0, 0, 0, 0, 0x27214038, 3 };
+PINFO(pclk_hdcp0_trng_info)	= { 0, 0, 0, 0, 0, 0, 0x2721403c, 0 };
+PINFO(hclk_hdcp_key0_info)	= { 0, 0, 0, 0, 0, 0, 0x2721403c, 3 };
+PINFO(pclk_edp_s_info)		= { 0, 0, 0, 0, 0, 0, 0x2721403c, 5 };
+
+struct pvtpll_table {
+	unsigned int rate;
+	uint32_t length;
+	uint32_t length_frac;
+	uint32_t length_low;
+	uint32_t length_low_frac;
+	uint32_t ring_sel;
+	uint32_t volt_sel_thr;
+};
+
+struct sys_clk_info_t {
+	struct pvtpll_table *cpul_table;
+	struct pvtpll_table *cci_table;
+	struct pvtpll_table *cpub_table;
+	struct pvtpll_table *gpu_table;
+	struct pvtpll_table *npu_table;
+	unsigned int cpul_rate_count;
+	unsigned int cci_rate_count;
+	unsigned int cpub_rate_count;
+	unsigned int gpu_rate_count;
+	unsigned int npu_rate_count;
+	unsigned long cpul_rate;
+	unsigned long cci_rate;
+	unsigned long cpub_rate;
+	unsigned long gpu_rate;
+	unsigned long npu_rate;
+};
+
+struct otp_opp_info {
+	uint16_t min_freq;
+	uint16_t max_freq;
+	uint8_t volt;
+	uint8_t length;
+} __packed;
+
+#define RK3576_SCMI_CLOCK(_id, _name, _data, _table, _cnt, _is_s)	\
+rk_scmi_clock_t _name = {						\
+	.id	= _id,							\
+	.name = #_name,							\
+	.clk_ops = _data,						\
+	.rate_table = _table,						\
+	.rate_cnt = _cnt,						\
+	.is_security = _is_s,						\
+}
+
+#define RK3576_SCMI_CLOCK_COM(_id, _name,  _parent_table, _info, _data,	\
+			     _table, is_d, _is_s)			\
+rk_scmi_clock_t _name = {						\
+	.id	= _id,							\
+	.name = #_name,							\
+	.parent_table = _parent_table,					\
+	.info = _info,							\
+	.clk_ops = _data,						\
+	.rate_table = _table,						\
+	.rate_cnt = ARRAY_SIZE(_table),					\
+	.is_dynamic_prate = is_d,					\
+	.is_security = _is_s,						\
+}
+
+#define ROCKCHIP_PVTPLL(_rate, _sel, _len, _len_frac)			\
+{									\
+	.rate = _rate##U,						\
+	.ring_sel = _sel,						\
+	.length = _len,							\
+	.length_frac = _len_frac,					\
+}
+
+static struct pvtpll_table rk3576_cpul_pvtpll_table[] = {
+	/* rate_hz, ring_sel, length, length_frac */
+	ROCKCHIP_PVTPLL(2016000000, 0, 6, 0),
+	ROCKCHIP_PVTPLL(1920000000, 0, 6, 1),
+	ROCKCHIP_PVTPLL(1800000000, 0, 6, 1),
+	ROCKCHIP_PVTPLL(1608000000, 0, 6, 1),
+	ROCKCHIP_PVTPLL(1416000000, 0, 8, 0),
+	ROCKCHIP_PVTPLL(1200000000, 0, 11, 0),
+	ROCKCHIP_PVTPLL(1008000000, 0, 17, 0),
+	ROCKCHIP_PVTPLL(816000000, 0, 26, 0),
+	ROCKCHIP_PVTPLL(600000000, 0, 0, 0),
+	ROCKCHIP_PVTPLL(408000000, 0, 0, 0),
+	{ /* sentinel */ },
+};
+
+static struct pvtpll_table rk3576_cci_pvtpll_table[] = {
+	/* cpul_rate_hz, ring_sel, length, length_frac */
+	ROCKCHIP_PVTPLL(2016000000 / 2, 0, 27, 0),
+	ROCKCHIP_PVTPLL(1920000000 / 2, 0, 28, 0),
+	ROCKCHIP_PVTPLL(1800000000 / 2, 0, 28, 0),
+	ROCKCHIP_PVTPLL(1608000000 / 2, 0, 30, 0),
+	ROCKCHIP_PVTPLL(1416000000 / 2, 0, 34, 0),
+	ROCKCHIP_PVTPLL(1200000000 / 2, 0, 34, 0),
+	{ /* sentinel */ },
+};
+
+static struct pvtpll_table rk3576_cpub_pvtpll_table[] = {
+	/* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */
+	ROCKCHIP_PVTPLL(2208000000, 0, 4, 3),
+	ROCKCHIP_PVTPLL(2112000000, 0, 5, 0),
+	ROCKCHIP_PVTPLL(2016000000, 0, 5, 0),
+	ROCKCHIP_PVTPLL(1800000000, 0, 5, 0),
+	ROCKCHIP_PVTPLL(1608000000, 0, 5, 0),
+	ROCKCHIP_PVTPLL(1416000000, 0, 7, 0),
+	ROCKCHIP_PVTPLL(1200000000, 0, 11, 0),
+	ROCKCHIP_PVTPLL(1008000000, 0, 17, 0),
+	ROCKCHIP_PVTPLL(816000000, 0, 26, 0),
+	ROCKCHIP_PVTPLL(600000000, 0, 0, 0),
+	ROCKCHIP_PVTPLL(408000000, 0, 0, 0),
+	{ /* sentinel */ },
+};
+
+static struct pvtpll_table rk3576_gpu_pvtpll_table[] = {
+	/* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */
+	ROCKCHIP_PVTPLL(900000000, 0, 20, 0),
+	ROCKCHIP_PVTPLL(800000000, 0, 21, 0),
+	ROCKCHIP_PVTPLL(700000000, 0, 21, 0),
+	ROCKCHIP_PVTPLL(600000000, 0, 23, 0),
+	ROCKCHIP_PVTPLL(500000000, 0, 32, 0),
+	ROCKCHIP_PVTPLL(400000000, 0, 48, 0),
+	ROCKCHIP_PVTPLL(300000000, 0, 63, 0),
+	ROCKCHIP_PVTPLL(200000000, 0, 0, 0),
+	{ /* sentinel */ },
+};
+
+static struct pvtpll_table rk3576_npu_pvtpll_table[] = {
+	/* rate_hz, ring_sel, length, length_frac, length_low, length_low_frac */
+	ROCKCHIP_PVTPLL(950000000, 0, 16, 0),
+	ROCKCHIP_PVTPLL(900000000, 0, 17, 0),
+	ROCKCHIP_PVTPLL(800000000, 0, 18, 0),
+	ROCKCHIP_PVTPLL(700000000, 0, 22, 0),
+	ROCKCHIP_PVTPLL(600000000, 0, 25, 0),
+	ROCKCHIP_PVTPLL(500000000, 0, 35, 0),
+	ROCKCHIP_PVTPLL(400000000, 0, 46, 0),
+	ROCKCHIP_PVTPLL(300000000, 0, 63, 0),
+	ROCKCHIP_PVTPLL(200000000, 0, 0, 0),
+	{ /* sentinel */ },
+};
+
+static unsigned long rk3576_cpul_rates[] = {
+	408000000, 600000000, 816000000, 1008000000,
+	1200000000, 1416000000, 1608000000, 1800000000,
+	2016000000, 2208000000, 2304000063
+};
+
+static unsigned long rk3576_cpub_rates[] = {
+	408000000, 600000000, 816000000, 1008000000,
+	1200000000, 1416000000, 1608000000, 1800000000,
+	2016000000, 2208000000, 2304000000, 2400000063
+};
+
+static unsigned long rk3576_gpu_rates[] = {
+	200000000, 300000000, 400000000, 500000000,
+	600000000, 700000000, 800000000, 900000000,
+	1000000063
+};
+
+static unsigned long rk3576_npu_rates[] = {
+	200000000, 300000000, 400000000, 500000000,
+	600000000, 700000000, 800000000, 900000000,
+	1000000063
+};
+
+static unsigned long rk3576_common_rates[] = {
+	400000, 24000000, 58000000, 100000000, 116000000, 175000000, 350000000,
+};
+
+static unsigned long rk3576_aclk_secure_s_rates[] = {
+	116000000, 175000000, 350000000,
+};
+
+static int aclk_crypto_s_enable;
+static int aclk_klad_enable;
+static spinlock_t crypto_lock;
+static bool cpub_suspended;
+
+static struct sys_clk_info_t sys_clk_info;
+static int clk_scmi_cci_set_rate(rk_scmi_clock_t *clock, unsigned long rate);
+
+static struct pvtpll_table *rkclk_get_pvtpll_config(struct pvtpll_table *table,
+						    unsigned int count,
+						    unsigned int freq_hz)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (freq_hz == table[i].rate)
+			return &table[i];
+	}
+	return NULL;
+}
+
+static int clk_scmi_set_low_length(struct pvtpll_table *pvtpll, unsigned int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (pvtpll[i].length_low) {
+			pvtpll[i].length = pvtpll[i].length_low;
+			pvtpll[i].length_frac = pvtpll[i].length_low_frac;
+		}
+	}
+
+	return 0;
+}
+
+static int clk_cpul_set_rate(unsigned long rate, enum pll_type_sel type)
+{
+	struct pvtpll_table *pvtpll;
+	int div;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpul_table,
+					 sys_clk_info.cpul_rate_count, rate);
+	if (pvtpll == NULL)
+		return SCMI_INVALID_PARAMETERS;
+
+	/*
+	 *               |-\
+	 * -----lpll-----|  \
+	 *               |   \                                        |-\
+	 * -----gpll-----|mux|--litcore unclean src--[div]--[autocs]--|  \
+	 *               |   /                                        |   \
+	 * --pvtpll src--|  /                           --pvtpll src--|mux|--litcore--
+	 *               |-/                                          |   /
+	 *                                       --litcore clean src--|  /
+	 *                                                            |-/
+	 */
+	if (PVTPLL_NEED(type, pvtpll->length)) {
+		/* set ring sel and length */
+		mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_LEN,
+			      0x1dff0000 |
+			      (pvtpll->ring_sel << 10) |
+			      (pvtpll->length << 2) |
+			      (pvtpll->length_frac));
+		/* set cal cnt = 24, T = 1us */
+		mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
+		/* enable pvtpll */
+		mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
+		/* start pvtpll */
+		mmio_write_32(PVTPLL_LITCORE_BASE + RK3576_PVTPLL_GCK_CFG,  0x00230023);
+
+		/* set pvtpll_src parent from 24MHz/32KHz to pvtpll */
+		mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1),
+			      CPUL_PVTPLL_PATH_PVTPLL);
+
+		/* set litcore unclean_src parent to pvtpll_src */
+		mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
+			      CPUL_CLK_PATH_NOR_PVTPLL);
+		/*
+		 * set litcore parent from pvtpll_src to unclean_src,
+		 * because autocs is on litcore unclean_src.
+		 */
+		mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1),
+			      CPUL_CLK_PATH_LPLL);
+		/* set litcore unclean_src div to 0 */
+		mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
+			      CLKDIV_5BITS_SHF(0, 7));
+
+		return 0;
+	}
+	/* set litcore unclean_src div */
+	div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
+	mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
+		      CLKDIV_5BITS_SHF(div, 7));
+	/* set litcore unclean_src parent to gpll */
+	mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0),
+		      CPUL_CLK_PATH_NOR_GPLL);
+	/* set litcore parent to unclean_src */
+	mmio_write_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1),
+		      CPUL_CLK_PATH_LPLL);
+
+	return 0;
+}
+
+static int clk_scmi_cpul_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
+{
+	int ret;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	ret = clk_cpul_set_rate(rate, PLL_SEL_AUTO);
+	if (ret == 0) {
+		sys_clk_info.cpul_rate = rate;
+		ret = clk_scmi_cci_set_rate(clock, rate / 2);
+	}
+
+	return ret;
+}
+
+static unsigned long rk3576_lpll_get_rate(void)
+{
+	unsigned int m, p, s, k;
+	uint64_t rate64 = 24000000, postdiv;
+	int mode;
+
+	mode = mmio_read_32(LITTLE_CRU_BASE + CRU_MODE_CON) &
+	       0x3;
+
+	if (mode == 0)
+		return rate64;
+
+	m = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(16)) >>
+		 CRU_PLLCON0_M_SHIFT) &
+		CRU_PLLCON0_M_MASK;
+	p = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(17)) >>
+		    CRU_PLLCON1_P_SHIFT) &
+		   CRU_PLLCON1_P_MASK;
+	s = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(17)) >>
+		  CRU_PLLCON1_S_SHIFT) &
+		 CRU_PLLCON1_S_MASK;
+	k = (mmio_read_32(CCI_CRU_BASE + CRU_PLL_CON(18)) >>
+		    CRU_PLLCON2_K_SHIFT) &
+		   CRU_PLLCON2_K_MASK;
+
+	rate64 *= m;
+	rate64 = rate64 / p;
+
+	if (k != 0) {
+		/* fractional mode */
+		uint64_t frac_rate64 = 24000000 * k;
+
+		postdiv = p * 65536;
+		frac_rate64 = frac_rate64 / postdiv;
+		rate64 += frac_rate64;
+	}
+	rate64 = rate64 >> s;
+
+	return (unsigned long)rate64;
+}
+
+static unsigned long clk_scmi_cpul_get_rate(rk_scmi_clock_t *clock)
+{
+	int src, div;
+
+	src = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(1)) & 0x00c0;
+	src = src >> 6;
+	if (src == 1)
+		return sys_clk_info.cpul_rate;
+
+	src = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(0)) & 0x3000;
+	src = src >> 12;
+	div = mmio_read_32(LITTLE_CRU_BASE + LCORE_CRU_CLKSEL_CON(6)) & 0x0f80;
+	div = div >> 7;
+	switch (src) {
+	case 0:
+		return rk3576_lpll_get_rate();
+	case 1:
+		/* Make the return rate is equal to the set rate */
+		if (sys_clk_info.cpul_rate != 0)
+			return sys_clk_info.cpul_rate;
+		else
+			return GPLL_RATE / (div + 1);
+	case 2:
+		return sys_clk_info.cpul_rate;
+	default:
+		return 0;
+	}
+}
+
+static int clk_scmi_cpul_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	return 0;
+}
+
+static int clk_cpub_set_rate(unsigned long rate, enum pll_type_sel type)
+{
+	struct pvtpll_table *pvtpll;
+	int div;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpub_table,
+					 sys_clk_info.cpub_rate_count, rate);
+	if (pvtpll == NULL)
+		return SCMI_INVALID_PARAMETERS;
+
+	/*
+	 *               |-\
+	 * -----bpll-----|  \
+	 *               |   \                                        |-\
+	 * -----gpll-----|mux|--bigcore unclean src--[div]--[autocs]--|  \
+	 *               |   /                                        |   \
+	 * --pvtpll src--|  /                           --pvtpll src--|mux|--bigcore--
+	 *               |-/                                          |   /
+	 *                                       --bigcore clean src--|  /
+	 *                                                            |-/
+	 */
+	if (PVTPLL_NEED(type, pvtpll->length) != 0) {
+		/* set ring sel and length */
+		mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_LEN,
+			      0x1dff0000 |
+			      (pvtpll->ring_sel << 10) |
+			      (pvtpll->length << 2) |
+			      (pvtpll->length_frac));
+		/* set cal cnt = 24, T = 1us */
+		mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
+		/* enable pvtpll */
+		mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
+		/* start pvtpll */
+		mmio_write_32(PVTPLL_BIGCORE_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
+
+		/* set pvtpll_src parent from 24MHz/32KHz to pvtpll */
+		mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(2),
+			      CPUB_PVTPLL_PATH_PVTPLL);
+
+		/* set bigcore unclean_src parent to pvtpll_src */
+		mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
+			      CPUB_CLK_PATH_NOR_PVTPLL);
+		/*
+		 * set bigcore parent from pvtpll_src to unclean_src,
+		 * because autocs is on bigcore unclean_src.
+		 */
+		mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
+			      CPUB_CLK_PATH_BPLL);
+
+		/* set bigcore unclean_src div to 0 */
+		mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
+			      CLKDIV_5BITS_SHF(0, 7));
+
+		return 0;
+	}
+
+	/* set bigcore unclean_src div */
+	div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
+	mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
+		      CLKDIV_5BITS_SHF(div, 7));
+	/* set bigcore unclean_src parent to gpll */
+	mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
+		      CPUB_CLK_PATH_NOR_GPLL);
+	/* set bigcore parent to unclean_src */
+	mmio_write_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1),
+		      CPUB_CLK_PATH_BPLL);
+
+	return 0;
+}
+
+static int clk_scmi_cpub_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
+{
+	int ret;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	if ((rate & OPP_LENGTH_LOW) != 0) {
+		clk_scmi_set_low_length(sys_clk_info.cpub_table,
+					sys_clk_info.cpub_rate_count);
+		return 0;
+	}
+
+	ret = clk_cpub_set_rate(rate, PLL_SEL_AUTO);
+	if (ret == 0)
+		sys_clk_info.cpub_rate = rate;
+
+	return ret;
+}
+
+static unsigned long rk3576_bpll_get_rate(void)
+{
+	unsigned int m, p, s, k;
+	uint64_t rate64 = 24000000, postdiv;
+	int mode;
+
+	mode = mmio_read_32(CRU_BASE + CRU_MODE_CON) &
+	       0x3;
+
+	if (mode == 0)
+		return rate64;
+
+	m = (mmio_read_32(CRU_BASE + CRU_PLL_CON(0)) >>
+		 CRU_PLLCON0_M_SHIFT) &
+		CRU_PLLCON0_M_MASK;
+	p = (mmio_read_32(CRU_BASE + CRU_PLL_CON(1)) >>
+		    CRU_PLLCON1_P_SHIFT) &
+		   CRU_PLLCON1_P_MASK;
+	s = (mmio_read_32(CRU_BASE + CRU_PLL_CON(1)) >>
+		  CRU_PLLCON1_S_SHIFT) &
+		 CRU_PLLCON1_S_MASK;
+	k = (mmio_read_32(CRU_BASE + CRU_PLL_CON(2)) >>
+		    CRU_PLLCON2_K_SHIFT) &
+		   CRU_PLLCON2_K_MASK;
+
+	rate64 *= m;
+	rate64 = rate64 / p;
+
+	if (k != 0) {
+		/* fractional mode */
+		uint64_t frac_rate64 = 24000000 * k;
+
+		postdiv = p * 65536;
+		frac_rate64 = frac_rate64 / postdiv;
+		rate64 += frac_rate64;
+	}
+	rate64 = rate64 >> s;
+
+	return (unsigned long)rate64;
+}
+
+static unsigned long clk_scmi_cpub_get_rate(rk_scmi_clock_t *clock)
+{
+	int value, src, div;
+
+	if (cpub_suspended != 0)
+		return sys_clk_info.cpub_rate;
+
+	value = mmio_read_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1));
+	src = (value & 0xc000) >> 14;
+	if (src == 1)
+		return sys_clk_info.cpub_rate;
+
+	value = mmio_read_32(BIGCORE_CRU_BASE + BCORE_CRU_CLKSEL_CON(1));
+	src = (value & 0x3000) >> 12;
+	div = (value & 0x0f80) >> 7;
+	switch (src) {
+	case 0:
+		return rk3576_bpll_get_rate();
+	case 1:
+		/* Make the return rate is equal to the set rate */
+		if (sys_clk_info.cpub_rate != 0)
+			return sys_clk_info.cpub_rate;
+		else
+			return GPLL_RATE / (div + 1);
+	case 2:
+		return sys_clk_info.cpub_rate;
+	default:
+		return 0;
+	}
+}
+
+static int clk_scmi_cpub_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	return 0;
+}
+
+static unsigned long clk_scmi_cci_get_rate(rk_scmi_clock_t *clock)
+{
+	int src, div;
+
+	src = mmio_read_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4)) & 0x3000;
+	src = src >> 12;
+	if (src == 1)
+		return sys_clk_info.cci_rate;
+
+	div = mmio_read_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4)) & 0xf80;
+	div = div >> 7;
+	switch (src) {
+	case 0:
+		return OSC_HZ;
+	case 1:
+		return sys_clk_info.cci_rate;
+	case 2:
+		return GPLL_RATE / (div + 1);
+	case 3:
+		return rk3576_lpll_get_rate() / (div + 1);
+	default:
+		return 0;
+	}
+}
+
+static int clk_cci_set_rate(unsigned long rate, enum pll_type_sel type)
+{
+	struct pvtpll_table *pvtpll;
+	uint32_t pvtpll_en = 0;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cci_table,
+					 sys_clk_info.cci_rate_count, rate);
+
+	/* set pvtpll */
+	if ((pvtpll != 0) && (PVTPLL_NEED(type, pvtpll->length) != 0)) {
+		/* set ring sel and length */
+		mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_LEN,
+			      0x1dff0000 |
+			      (pvtpll->ring_sel << 10) |
+			      (pvtpll->length << 2) |
+			      (pvtpll->length_frac));
+		/* set cal cnt = 24, T = 1us */
+		mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
+		/* enable pvtpll */
+		pvtpll_en = mmio_read_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG);
+		if (pvtpll_en && 0x22 != 0x22)
+			mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
+		/* start pvtpll */
+		mmio_write_32(PVTPLL_CCI_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
+
+		/* set cci mux pvtpll */
+		mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
+			      CCI_PVTPLL_PATH_PVTPLL);
+		mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
+			      SCLK_CCI_PATH_PVTPLL);
+		mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
+			      CLKDIV_5BITS_SHF(0, 7));
+		sys_clk_info.cci_rate = rate;
+		return 0;
+	}
+	sys_clk_info.cci_rate = 594000000;
+	/* set cci div */
+	mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
+		      CLKDIV_5BITS_SHF(1, 7));
+	/* set cci mux gpll */
+	mmio_write_32(CCI_CRU_BASE + CCICRU_CLKSEL_CON(4),
+		      SCLK_CCI_PATH_NOR_GPLL);
+
+	return 0;
+}
+
+static int clk_scmi_cci_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
+{
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	return clk_cci_set_rate(rate, PLL_SEL_AUTO);
+}
+
+static int clk_scmi_cci_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	return 0;
+}
+
+static unsigned long clk_scmi_gpu_get_rate(rk_scmi_clock_t *clock)
+{
+	int div, src;
+
+	if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x100) != 0)
+		return sys_clk_info.gpu_rate;
+
+	div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x1f;
+	src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(165)) & 0x00e0;
+	src = src >> 5;
+	switch (src) {
+	case 0:
+		/* Make the return rate is equal to the set rate */
+		if (sys_clk_info.gpu_rate != 0)
+			return sys_clk_info.gpu_rate;
+		else
+			return GPLL_RATE / (div + 1);
+	case 1:
+		return CPLL_RATE / (div + 1);
+	case 2:
+		return AUPLL_RATE / (div + 1);
+	case 3:
+		return SPLL_RATE / (div + 1);
+	case 4:
+		return rk3576_lpll_get_rate() / (div + 1);
+	default:
+		return 0;
+	}
+}
+
+static int clk_gpu_set_rate(unsigned long rate, enum pll_type_sel type)
+{
+	struct pvtpll_table *pvtpll;
+	int div;
+
+	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.gpu_table,
+					 sys_clk_info.gpu_rate_count, rate);
+	if (pvtpll == NULL)
+		return SCMI_INVALID_PARAMETERS;
+
+	if (PVTPLL_NEED(type, pvtpll->length) != 0) {
+		/* set ring sel and length */
+		mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_LEN,
+			      0x1dff0000 |
+			      (pvtpll->ring_sel << 10) |
+			      (pvtpll->length << 2) |
+			      (pvtpll->length_frac));
+		/* set cal cnt = 24, T = 1us */
+		mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
+		/* enable pvtpll */
+		mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
+		/* start pvtpll */
+		mmio_write_32(PVTPLL_GPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
+		/* set gpu mux pvtpll */
+		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
+			      GPU_PVTPLL_PATH_PVTPLL);
+		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
+			      GPU_CLK_PATH_PVTPLL);
+		return 0;
+	}
+
+	/* set gpu div */
+	div = DIV_ROUND_UP(GPLL_RATE, rate);
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
+		      CLKDIV_5BITS_SHF(div - 1, 0));
+	/* set gpu mux gpll */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
+		      GPU_CLK_PATH_NOR_GPLL);
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(165),
+		      GPU_CLK_PATH_NOR_PLL);
+
+	return 0;
+}
+
+static int clk_scmi_gpu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
+{
+	int ret;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	if ((rate & OPP_LENGTH_LOW) != 0) {
+		clk_scmi_set_low_length(sys_clk_info.gpu_table,
+					sys_clk_info.gpu_rate_count);
+		return 0;
+	}
+
+	ret = clk_gpu_set_rate(rate, PLL_SEL_AUTO);
+	if (ret == 0)
+		sys_clk_info.gpu_rate = rate;
+
+	return ret;
+}
+
+static int clk_scmi_gpu_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	return 0;
+}
+
+static unsigned long clk_scmi_npu_get_rate(rk_scmi_clock_t *clock)
+{
+	int div, src, div_src;
+
+	if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x8000) != 0)
+		return sys_clk_info.npu_rate;
+
+	div_src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x07c;
+	div_src = div_src >> 2;
+	src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x0180;
+	src = src >> 7;
+	div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(86)) & 0x7c00;
+	div = div >> 10;
+	switch (src) {
+	case 0:
+		/* Make the return rate is equal to the set rate */
+		if (sys_clk_info.npu_rate != 0)
+			return sys_clk_info.npu_rate;
+		else
+			return GPLL_RATE / (div_src + 1)  / (div + 1);
+	case 1:
+		return CPLL_RATE / (div_src + 1)  / (div + 1);
+	case 2:
+		return AUPLL_RATE / (div_src + 1)  / (div + 1);
+	case 3:
+		return SPLL_RATE / (div_src + 1)  / (div + 1);
+	default:
+		return 0;
+	}
+}
+
+static int clk_npu_set_rate(unsigned long rate, enum pll_type_sel type)
+{
+	struct pvtpll_table *pvtpll;
+	int div;
+
+	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.npu_table,
+					 sys_clk_info.npu_rate_count, rate);
+	if (pvtpll == NULL)
+		return SCMI_INVALID_PARAMETERS;
+
+	if (PVTPLL_NEED(type, pvtpll->length) != 0) {
+		/* set ring sel and length */
+		mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_LEN,
+			      0x1dff0000 |
+			      (pvtpll->ring_sel << 10) |
+			      (pvtpll->length << 2) |
+			      (pvtpll->length_frac));
+		/* set cal cnt = 24, T = 1us */
+		mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CAL_CNT, 0x18);
+		/* enable pvtpll */
+		mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00220022);
+		/* start pvtpll */
+		mmio_write_32(PVTPLL_NPU_BASE + RK3576_PVTPLL_GCK_CFG, 0x00230023);
+		/* set npu mux pvtpll */
+		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+			      NPU_PVTPLL_PATH_PVTPLL);
+		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+			      NPU_CLK_PATH_PVTPLL);
+		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+			      CLKDIV_5BITS_SHF(0, 10));
+		return 0;
+	}
+
+	/* set npu div */
+	div = DIV_ROUND_UP(GPLL_RATE, rate);
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+		      CLKDIV_5BITS_SHF(div - 1, 2));
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+		      CLKDIV_5BITS_SHF(0, 10));
+	/* set npu mux gpll */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+		      NPU_CLK_PATH_NOR_GPLL);
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(86),
+		      NPU_CLK_PATH_NOR_PLL);
+
+	return 0;
+}
+
+static int clk_scmi_npu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
+{
+	int ret;
+
+	if (rate == 0)
+		return SCMI_INVALID_PARAMETERS;
+
+	if ((rate & OPP_LENGTH_LOW) != 0) {
+		clk_scmi_set_low_length(sys_clk_info.npu_table,
+					sys_clk_info.npu_rate_count);
+		return 0;
+	}
+
+	ret = clk_npu_set_rate(rate, PLL_SEL_AUTO);
+	if (ret == 0)
+		sys_clk_info.npu_rate = rate;
+
+	return ret;
+}
+
+static int clk_scmi_npu_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	return 0;
+}
+
+int clk_scmi_crypto_set_status(rk_scmi_clock_t *clock, bool status)
+{
+	spin_lock(&crypto_lock);
+
+	if (clock->id == ACLK_CRYPTO_S)
+		aclk_crypto_s_enable = status;
+	else
+		aclk_klad_enable = status;
+
+	if ((aclk_crypto_s_enable != 0) || (aclk_klad_enable != 0))
+		clk_scmi_common_set_status(clock, 1);
+	else
+		clk_scmi_common_set_status(clock, 0);
+
+	spin_unlock(&crypto_lock);
+	return 0;
+}
+
+static int clk_scmi_common_set_status_critical(rk_scmi_clock_t *clock, bool status)
+{
+	return 0;
+}
+
+static const struct rk_clk_ops clk_scmi_cpul_ops = {
+	.get_rate = clk_scmi_cpul_get_rate,
+	.set_rate = clk_scmi_cpul_set_rate,
+	.set_status = clk_scmi_cpul_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_cci_ops = {
+	.get_rate = clk_scmi_cci_get_rate,
+	.set_rate = clk_scmi_cci_set_rate,
+	.set_status = clk_scmi_cci_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_cpub_ops = {
+	.get_rate = clk_scmi_cpub_get_rate,
+	.set_rate = clk_scmi_cpub_set_rate,
+	.set_status = clk_scmi_cpub_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_gpu_ops = {
+	.get_rate = clk_scmi_gpu_get_rate,
+	.set_rate = clk_scmi_gpu_set_rate,
+	.set_status = clk_scmi_gpu_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_npu_ops = {
+	.get_rate = clk_scmi_npu_get_rate,
+	.set_rate = clk_scmi_npu_set_rate,
+	.set_status = clk_scmi_npu_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_ops_com_critical = {
+	.get_rate = clk_scmi_common_get_rate,
+	.set_rate = clk_scmi_common_set_rate,
+	.set_status = clk_scmi_common_set_status_critical,
+};
+
+static const struct rk_clk_ops clk_scmi_ops_com = {
+	.get_rate = clk_scmi_common_get_rate,
+	.set_rate = clk_scmi_common_set_rate,
+	.set_status = clk_scmi_common_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_ops_gate = {
+	.get_rate = clk_scmi_common_get_rate,
+	.set_status = clk_scmi_common_set_status,
+};
+
+static const struct rk_clk_ops clk_scmi_ops_crypto = {
+	.get_rate = clk_scmi_common_get_rate,
+	.set_status = clk_scmi_crypto_set_status,
+};
+
+RK3576_SCMI_CLOCK(ARMCLK_L, scmi_armclkl, &clk_scmi_cpul_ops, rk3576_cpul_rates, ARRAY_SIZE(rk3576_cpul_rates), false);
+RK3576_SCMI_CLOCK(ACLK_CCI_ROOT, scmi_aclk_cci, &clk_scmi_cci_ops, rk3576_cpul_rates, ARRAY_SIZE(rk3576_cpul_rates), false);
+RK3576_SCMI_CLOCK(ARMCLK_B, scmi_armclkb, &clk_scmi_cpub_ops, rk3576_cpub_rates, ARRAY_SIZE(rk3576_cpub_rates), false);
+RK3576_SCMI_CLOCK(CLK_GPU, scmi_clk_gpu, &clk_scmi_gpu_ops, rk3576_gpu_rates, ARRAY_SIZE(rk3576_gpu_rates), false);
+RK3576_SCMI_CLOCK(CLK_RKNN_DSU0, scmi_clk_npu, &clk_scmi_npu_ops, rk3576_npu_rates, ARRAY_SIZE(rk3576_npu_rates), false);
+RK3576_SCMI_CLOCK_COM(CLK_STIMER0_ROOT, clk_stimer0_root, p_100m_24m, clk_stimer0_root_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(CLK_STIMER1_ROOT, clk_stimer1_root, p_100m_24m, clk_stimer1_root_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(PCLK_SECURE_S, pclk_secure_s, p_116m_58m_24m, pclk_secure_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(HCLK_SECURE_S, hclk_secure_s, p_175m_116m_58m_24m, hclk_secure_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(ACLK_SECURE_S, aclk_secure_s, p_350m_175m_116m_24m, aclk_secure_s_info, &clk_scmi_ops_com_critical, rk3576_aclk_secure_s_rates, false, false);
+RK3576_SCMI_CLOCK_COM(CLK_PKA_CRYPTO_S, clk_pka_crypto_s, p_350m_175m_116m_24m, clk_pka_crypto_s_info, &clk_scmi_ops_com, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(HCLK_VO1_S, hclk_vo1_s, p_175m_116m_58m_24m, hclk_vo1_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(PCLK_VO1_S, pclk_vo1_s, p_116m_58m_24m, pclk_vo1_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(HCLK_VO0_S, hclk_vo0_s, p_175m_116m_58m_24m, hclk_vo0_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(PCLK_VO0_S, pclk_vo0_s, p_116m_58m_24m, pclk_vo0_s_info, &clk_scmi_ops_com_critical, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(PCLK_KLAD, pclk_klad, p_pclk_secure_s, pclk_klad_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(HCLK_CRYPTO_S, hclk_crypto_s, p_hclk_secure_s, hclk_crypto_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(HCLK_KLAD, hclk_klad, p_hclk_secure_s, hclk_klad_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(ACLK_CRYPTO_S, aclk_crypto_s, p_aclk_secure_s, aclk_crypto_s_info, &clk_scmi_ops_crypto, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(HCLK_TRNG_S, hclk_trng_s, p_hclk_secure_s, hclk_trng_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(PCLK_OTPC_S, plk_otpc_s, p_pclk_secure_s, pclk_otpc_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(CLK_OTPC_S, clk_otpc_s, p_24m, clk_otpc_s_info, &clk_scmi_ops_gate, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(PCLK_WDT_S, pclk_wdt_s, p_pclk_secure_s, pclk_wdt_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(TCLK_WDT_S, tclk_wdt_s, p_24m, tclk_wdt_s_info, &clk_scmi_ops_gate, rk3576_common_rates, false, true);
+RK3576_SCMI_CLOCK_COM(PCLK_HDCP0_TRNG, pclk_hdcp0_trng, p_pclk_vo0_s, pclk_hdcp0_trng_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(PCLK_HDCP1_TRNG, pclk_hdcp1_trng, p_pclk_vo1_s, pclk_hdcp1_trng_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(HCLK_HDCP_KEY0, hclk_hdcp_key0, p_hclk_vo0_s, hclk_hdcp_key0_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(HCLK_HDCP_KEY1, hclk_hdcp_key1, p_hclk_vo1_s, hclk_hdcp_key1_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(PCLK_EDP_S, pclk_edp_s, p_pclk_vo0_s, pclk_edp_s_info, &clk_scmi_ops_gate, rk3576_common_rates, true, true);
+RK3576_SCMI_CLOCK_COM(ACLK_KLAD, aclk_klad, p_aclk_secure_s, aclk_crypto_s_info, &clk_scmi_ops_crypto, rk3576_common_rates, true, true);
+
+rk_scmi_clock_t *clock_table[] = {
+	[ARMCLK_L]		= &scmi_armclkl,
+	[ACLK_CCI_ROOT]		= &scmi_aclk_cci,
+	[ARMCLK_B]		= &scmi_armclkb,
+	[CLK_GPU]		= &scmi_clk_gpu,
+	[CLK_RKNN_DSU0]		= &scmi_clk_npu,
+	[CLK_STIMER0_ROOT]	= &clk_stimer0_root,
+	[CLK_STIMER1_ROOT]	= &clk_stimer1_root,
+	[PCLK_SECURE_S]		= &pclk_secure_s,
+	[HCLK_SECURE_S]		= &hclk_secure_s,
+	[ACLK_SECURE_S]		= &aclk_secure_s,
+	[CLK_PKA_CRYPTO_S]	= &clk_pka_crypto_s,
+	[HCLK_VO1_S]		= &hclk_vo1_s,
+	[PCLK_VO1_S]		= &pclk_vo1_s,
+	[HCLK_VO0_S]		= &hclk_vo0_s,
+	[PCLK_VO0_S]		= &pclk_vo0_s,
+	[PCLK_KLAD]		= &pclk_klad,
+	[HCLK_CRYPTO_S]		= &hclk_crypto_s,
+	[HCLK_KLAD]		= &hclk_klad,
+	[ACLK_CRYPTO_S]		= &aclk_crypto_s,
+	[HCLK_TRNG_S]		= &hclk_trng_s,
+	[PCLK_OTPC_S]		= &plk_otpc_s,
+	[CLK_OTPC_S]		= &clk_otpc_s,
+	[PCLK_WDT_S]		= &pclk_wdt_s,
+	[TCLK_WDT_S]		= &tclk_wdt_s,
+	[PCLK_HDCP0_TRNG]	= &pclk_hdcp0_trng,
+	[PCLK_HDCP1_TRNG]	= &pclk_hdcp1_trng,
+	[HCLK_HDCP_KEY0]	= &hclk_hdcp_key0,
+	[HCLK_HDCP_KEY1]	= &hclk_hdcp_key1,
+	[PCLK_EDP_S]		= &pclk_edp_s,
+	[ACLK_KLAD]		= &aclk_klad,
+};
+
+size_t rockchip_scmi_clock_count(unsigned int agent_id __unused)
+{
+	return CLK_NR_CLKS;
+}
+
+rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused,
+					 uint32_t clock_id)
+{
+	rk_scmi_clock_t *table = NULL;
+
+	if (clock_id < ARRAY_SIZE(clock_table)) {
+		table = clock_table[clock_id];
+		if (table == NULL)
+			return NULL;
+	}
+
+	if ((table != NULL) && (table->is_security == 0))
+		return table;
+	else
+		return NULL;
+
+	return NULL;
+}
+
+void pvtplls_cpub_suspend(void)
+{
+	clk_cpub_set_rate(408000000, PLL_SEL_NOR);
+	cpub_suspended = true;
+}
+
+void pvtplls_cpub_resume(void)
+{
+	cpub_suspended = false;
+	clk_cpub_set_rate(sys_clk_info.cpub_rate, PLL_SEL_AUTO);
+}
+
+void pvtplls_suspend(void)
+{
+	clk_cpul_set_rate(408000000, PLL_SEL_NOR);
+	clk_cci_set_rate(408000000, PLL_SEL_NOR);
+	clk_cpub_set_rate(408000000, PLL_SEL_NOR);
+}
+
+void pvtplls_resume(void)
+{
+	clk_cpul_set_rate(sys_clk_info.cpul_rate, PLL_SEL_AUTO);
+	clk_cci_set_rate(sys_clk_info.cci_rate, PLL_SEL_AUTO);
+	clk_cpub_set_rate(sys_clk_info.cpub_rate, PLL_SEL_AUTO);
+}
+
+void sys_reset_pvtplls_prepare(void)
+{
+	clk_gpu_set_rate(200000000, PLL_SEL_NOR);
+	clk_npu_set_rate(200000000, PLL_SEL_NOR);
+	clk_cpul_set_rate(408000000, PLL_SEL_NOR);
+	clk_cci_set_rate(408000000, PLL_SEL_NOR);
+	clk_cpub_set_rate(408000000, PLL_SEL_NOR);
+}
+
+int rockchip_opteed_clk_set_rate(uint64_t clk_idx, uint64_t rate)
+{
+	rk_scmi_clock_t *table;
+
+	if (clk_idx > CLK_NR_CLKS) {
+		INFO("%s: clk-%ld, %ld not supported\n", __func__, clk_idx, rate);
+		return SCMI_INVALID_PARAMETERS;
+	}
+
+	table = rockchip_scmi_get_clock(0, clk_idx);
+	if (table != NULL)
+		table->clk_ops->set_rate(table, rate);
+
+	return 0;
+}
+
+int rockchip_opteed_clk_get_rate(uint64_t clk_idx, uint64_t *rate)
+{
+	rk_scmi_clock_t *table;
+
+	if (clk_idx > CLK_NR_CLKS) {
+		INFO("%s: clk-%ld not supported\n", __func__, clk_idx);
+		return SCMI_INVALID_PARAMETERS;
+	}
+
+	table = rockchip_scmi_get_clock(0, clk_idx);
+	if (table != NULL)
+		*rate = (uint64_t)table->clk_ops->get_rate(table);
+	return 0;
+}
+
+int rockchip_opteed_clk_enable(uint64_t clk_idx, uint64_t enable)
+{
+	rk_scmi_clock_t *table;
+
+	if (clk_idx > CLK_NR_CLKS) {
+		INFO("%s: clk-%ld, %ld not supported\n", __func__, clk_idx, enable);
+		return SCMI_INVALID_PARAMETERS;
+	}
+
+	table = rockchip_scmi_get_clock(0, clk_idx);
+	if (table != NULL) {
+		if (enable != 0) {
+			table->clk_ops->set_status(table, enable);
+			table->enable_count++;
+		} else {
+			if (table->enable_count == 0)
+				return 0;
+			if (--table->enable_count > 0)
+				return 0;
+			table->clk_ops->set_status(table, enable);
+		}
+	}
+	return 0;
+}
+
+#define RK3576_CPUB_OPP_INFO_OFFSET	48
+#define RK3576_CPUL_OPP_INFO_OFFSET	54
+#define RK3576_CCI_OPP_INFO_OFFSET	60
+#define RK3576_NPU_OPP_INFO_OFFSET	66
+#define RK3576_GPU_OPP_INFO_OFFSET	72
+
+static void rockchip_init_pvtpll_table(void)
+{
+	sys_clk_info.cpul_table = rk3576_cpul_pvtpll_table;
+	sys_clk_info.cpul_rate_count = ARRAY_SIZE(rk3576_cpul_pvtpll_table);
+	sys_clk_info.cci_table = rk3576_cci_pvtpll_table;
+	sys_clk_info.cci_rate_count = ARRAY_SIZE(rk3576_cci_pvtpll_table);
+	sys_clk_info.cpub_table = rk3576_cpub_pvtpll_table;
+	sys_clk_info.cpub_rate_count = ARRAY_SIZE(rk3576_cpub_pvtpll_table);
+	sys_clk_info.gpu_table = rk3576_gpu_pvtpll_table;
+	sys_clk_info.gpu_rate_count = ARRAY_SIZE(rk3576_gpu_pvtpll_table);
+	sys_clk_info.npu_table = rk3576_npu_pvtpll_table;
+	sys_clk_info.npu_rate_count = ARRAY_SIZE(rk3576_npu_pvtpll_table);
+}
+
+void rockchip_clock_init(void)
+{
+	rockchip_init_pvtpll_table();
+}
+
+static int pvtpll_get_clk(uint64_t clock_id, struct pvtpll_table **table,
+			  unsigned int *count)
+{
+	switch (clock_id) {
+	case ARMCLK_L:
+		*table = sys_clk_info.cpul_table;
+		*count = sys_clk_info.cpul_rate_count;
+		break;
+	case ARMCLK_B:
+		*table = sys_clk_info.cpub_table;
+		*count = sys_clk_info.cpub_rate_count;
+		break;
+	case CLK_GPU:
+		*table = sys_clk_info.gpu_table;
+		*count = sys_clk_info.gpu_rate_count;
+		break;
+	case CLK_RKNN_DSU0:
+		*table = sys_clk_info.npu_table;
+		*count = sys_clk_info.npu_rate_count;
+		break;
+	default:
+		return -1;
+	}
+
+	if ((*table == NULL) || (*count == 0))
+		return -1;
+
+	return 0;
+}
+
+int pvtpll_volt_sel_adjust(uint64_t clock_id, uint64_t volt_sel)
+{
+	struct pvtpll_table *table = NULL;
+	uint32_t delta_len = 0;
+	unsigned int count = 0;
+	int i;
+
+	if (pvtpll_get_clk(clock_id, &table, &count) != 0)
+		return -1;
+
+	for (i = 0; i < count; i++) {
+		if (table[i].volt_sel_thr == 0)
+			continue;
+		if (volt_sel >= table[i].volt_sel_thr) {
+			delta_len = volt_sel - table[i].volt_sel_thr + 1;
+			table[i].length += delta_len;
+			if (table[i].length > RK3576_PVTPLL_MAX_LENGTH)
+				table[i].length = RK3576_PVTPLL_MAX_LENGTH;
+		}
+	}
+
+	return 0;
+}
diff --git a/plat/rockchip/rk3576/scmi/rk3576_clk.h b/plat/rockchip/rk3576/scmi/rk3576_clk.h
new file mode 100644
index 0000000..b2c00b9
--- /dev/null
+++ b/plat/rockchip/rk3576/scmi/rk3576_clk.h
@@ -0,0 +1,1151 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
+ */
+
+#ifndef __CLOCK_H__
+#define __CLOCK_H__
+
+/* cru-clocks indices */
+
+/* cru plls */
+#define PLL_BPLL			1
+#define PLL_LPLL			3
+#define PLL_VPLL			4
+#define PLL_AUPLL			5
+#define PLL_CPLL			6
+#define PLL_GPLL			7
+#define PLL_PPLL			9
+#define ARMCLK_L			10
+#define ARMCLK_B			11
+
+/* cru clocks */
+#define CLK_CPLL_DIV20			15
+#define CLK_CPLL_DIV10			16
+#define CLK_GPLL_DIV8			17
+#define CLK_GPLL_DIV6			18
+#define CLK_CPLL_DIV4			19
+#define CLK_GPLL_DIV4			20
+#define CLK_SPLL_DIV2			21
+#define CLK_GPLL_DIV3			22
+#define CLK_CPLL_DIV2			23
+#define CLK_GPLL_DIV2			24
+#define CLK_SPLL_DIV1			25
+#define PCLK_TOP_ROOT			26
+#define ACLK_TOP			27
+#define HCLK_TOP			28
+#define CLK_AUDIO_FRAC_0		29
+#define CLK_AUDIO_FRAC_1		30
+#define CLK_AUDIO_FRAC_2		31
+#define CLK_AUDIO_FRAC_3		32
+#define CLK_UART_FRAC_0			33
+#define CLK_UART_FRAC_1			34
+#define CLK_UART_FRAC_2			35
+#define CLK_UART1_SRC_TOP		36
+#define CLK_AUDIO_INT_0			37
+#define CLK_AUDIO_INT_1			38
+#define CLK_AUDIO_INT_2			39
+#define CLK_PDM0_SRC_TOP		40
+#define CLK_PDM1_OUT			41
+#define CLK_GMAC0_125M_SRC		42
+#define CLK_GMAC1_125M_SRC		43
+#define LCLK_ASRC_SRC_0			44
+#define LCLK_ASRC_SRC_1			45
+#define REF_CLK0_OUT_PLL		46
+#define REF_CLK1_OUT_PLL		47
+#define REF_CLK2_OUT_PLL		48
+#define REFCLKO25M_GMAC0_OUT		49
+#define REFCLKO25M_GMAC1_OUT		50
+#define CLK_CIFOUT_OUT			51
+#define CLK_GMAC0_RMII_CRU		52
+#define CLK_GMAC1_RMII_CRU		53
+#define CLK_OTPC_AUTO_RD_G		54
+#define CLK_OTP_PHY_G			55
+#define CLK_MIPI_CAMERAOUT_M0		56
+#define CLK_MIPI_CAMERAOUT_M1		57
+#define CLK_MIPI_CAMERAOUT_M2		58
+#define MCLK_PDM0_SRC_TOP		59
+#define HCLK_AUDIO_ROOT			60
+#define HCLK_ASRC_2CH_0			61
+#define HCLK_ASRC_2CH_1			62
+#define HCLK_ASRC_4CH_0			63
+#define HCLK_ASRC_4CH_1			64
+#define CLK_ASRC_2CH_0			65
+#define CLK_ASRC_2CH_1			66
+#define CLK_ASRC_4CH_0			67
+#define CLK_ASRC_4CH_1			68
+#define MCLK_SAI0_8CH_SRC		69
+#define MCLK_SAI0_8CH			70
+#define HCLK_SAI0_8CH			71
+#define HCLK_SPDIF_RX0			72
+#define MCLK_SPDIF_RX0			73
+#define HCLK_SPDIF_RX1			74
+#define MCLK_SPDIF_RX1			75
+#define MCLK_SAI1_8CH_SRC		76
+#define MCLK_SAI1_8CH			77
+#define HCLK_SAI1_8CH			78
+#define MCLK_SAI2_2CH_SRC		79
+#define MCLK_SAI2_2CH			80
+#define HCLK_SAI2_2CH			81
+#define MCLK_SAI3_2CH_SRC		82
+#define MCLK_SAI3_2CH			83
+#define HCLK_SAI3_2CH			84
+#define MCLK_SAI4_2CH_SRC		85
+#define MCLK_SAI4_2CH			86
+#define HCLK_SAI4_2CH			87
+#define HCLK_ACDCDIG_DSM		88
+#define MCLK_ACDCDIG_DSM		89
+#define CLK_PDM1			90
+#define HCLK_PDM1			91
+#define MCLK_PDM1			92
+#define HCLK_SPDIF_TX0			93
+#define MCLK_SPDIF_TX0			94
+#define HCLK_SPDIF_TX1			95
+#define MCLK_SPDIF_TX1			96
+#define CLK_SAI1_MCLKOUT		97
+#define CLK_SAI2_MCLKOUT		98
+#define CLK_SAI3_MCLKOUT		99
+#define CLK_SAI4_MCLKOUT		100
+#define CLK_SAI0_MCLKOUT		101
+#define HCLK_BUS_ROOT			102
+#define PCLK_BUS_ROOT			103
+#define ACLK_BUS_ROOT			104
+#define HCLK_CAN0			105
+#define CLK_CAN0			106
+#define HCLK_CAN1			107
+#define CLK_CAN1			108
+#define CLK_KEY_SHIFT			109
+#define PCLK_I2C1			110
+#define PCLK_I2C2			111
+#define PCLK_I2C3			112
+#define PCLK_I2C4			113
+#define PCLK_I2C5			114
+#define PCLK_I2C6			115
+#define PCLK_I2C7			116
+#define PCLK_I2C8			117
+#define PCLK_I2C9			118
+#define PCLK_WDT_BUSMCU			119
+#define TCLK_WDT_BUSMCU			120
+#define ACLK_GIC			121
+#define CLK_I2C1			122
+#define CLK_I2C2			123
+#define CLK_I2C3			124
+#define CLK_I2C4			125
+#define CLK_I2C5			126
+#define CLK_I2C6			127
+#define CLK_I2C7			128
+#define CLK_I2C8			129
+#define CLK_I2C9			130
+#define PCLK_SARADC			131
+#define CLK_SARADC			132
+#define PCLK_TSADC			133
+#define CLK_TSADC			134
+#define PCLK_UART0			135
+#define PCLK_UART2			136
+#define PCLK_UART3			137
+#define PCLK_UART4			138
+#define PCLK_UART5			139
+#define PCLK_UART6			140
+#define PCLK_UART7			141
+#define PCLK_UART8			142
+#define PCLK_UART9			143
+#define PCLK_UART10			144
+#define PCLK_UART11			145
+#define SCLK_UART0			146
+#define SCLK_UART2			147
+#define SCLK_UART3			148
+#define SCLK_UART4			149
+#define SCLK_UART5			150
+#define SCLK_UART6			151
+#define SCLK_UART7			152
+#define SCLK_UART8			153
+#define SCLK_UART9			154
+#define SCLK_UART10			155
+#define SCLK_UART11			156
+#define PCLK_SPI0			157
+#define PCLK_SPI1			158
+#define PCLK_SPI2			159
+#define PCLK_SPI3			160
+#define PCLK_SPI4			161
+#define CLK_SPI0			162
+#define CLK_SPI1			163
+#define CLK_SPI2			164
+#define CLK_SPI3			165
+#define CLK_SPI4			166
+#define PCLK_WDT0			167
+#define TCLK_WDT0			168
+#define PCLK_PWM1			169
+#define CLK_PWM1			170
+#define CLK_OSC_PWM1			171
+#define CLK_RC_PWM1			172
+#define PCLK_BUSTIMER0			173
+#define PCLK_BUSTIMER1			174
+#define CLK_TIMER0_ROOT			175
+#define CLK_TIMER0			176
+#define CLK_TIMER1			177
+#define CLK_TIMER2			178
+#define CLK_TIMER3			179
+#define CLK_TIMER4			180
+#define CLK_TIMER5			181
+#define PCLK_MAILBOX0			182
+#define PCLK_GPIO1			183
+#define DBCLK_GPIO1			184
+#define PCLK_GPIO2			185
+#define DBCLK_GPIO2			186
+#define PCLK_GPIO3			187
+#define DBCLK_GPIO3			188
+#define PCLK_GPIO4			189
+#define DBCLK_GPIO4			190
+#define ACLK_DECOM			191
+#define PCLK_DECOM			192
+#define DCLK_DECOM			193
+#define CLK_TIMER1_ROOT			194
+#define CLK_TIMER6			195
+#define CLK_TIMER7			196
+#define CLK_TIMER8			197
+#define CLK_TIMER9			198
+#define CLK_TIMER10			199
+#define CLK_TIMER11			200
+#define ACLK_DMAC0			201
+#define ACLK_DMAC1			202
+#define ACLK_DMAC2			203
+#define ACLK_SPINLOCK			204
+#define HCLK_I3C0			205
+#define HCLK_I3C1			206
+#define HCLK_BUS_CM0_ROOT		207
+#define FCLK_BUS_CM0_CORE		208
+#define CLK_BUS_CM0_RTC			209
+#define PCLK_PMU2			210
+#define PCLK_PWM2			211
+#define CLK_PWM2			212
+#define CLK_RC_PWM2			213
+#define CLK_OSC_PWM2			214
+#define CLK_FREQ_PWM1			215
+#define CLK_COUNTER_PWM1		216
+#define SAI_SCLKIN_FREQ			217
+#define SAI_SCLKIN_COUNTER		218
+#define CLK_I3C0			219
+#define CLK_I3C1			220
+#define PCLK_CSIDPHY1			221
+#define PCLK_DDR_ROOT			222
+#define PCLK_DDR_MON_CH0		223
+#define TMCLK_DDR_MON_CH0		224
+#define ACLK_DDR_ROOT			225
+#define HCLK_DDR_ROOT			226
+#define FCLK_DDR_CM0_CORE		227
+#define CLK_DDR_TIMER_ROOT		228
+#define CLK_DDR_TIMER0			229
+#define CLK_DDR_TIMER1			230
+#define TCLK_WDT_DDR			231
+#define PCLK_WDT			232
+#define PCLK_TIMER			233
+#define CLK_DDR_CM0_RTC			234
+#define ACLK_RKNN0			235
+#define ACLK_RKNN1			236
+#define HCLK_RKNN_ROOT			237
+#define CLK_RKNN_DSU0			238
+#define PCLK_NPUTOP_ROOT		239
+#define PCLK_NPU_TIMER			240
+#define CLK_NPUTIMER_ROOT		241
+#define CLK_NPUTIMER0			242
+#define CLK_NPUTIMER1			243
+#define PCLK_NPU_WDT			244
+#define TCLK_NPU_WDT			245
+#define ACLK_RKNN_CBUF			246
+#define HCLK_NPU_CM0_ROOT		247
+#define FCLK_NPU_CM0_CORE		248
+#define CLK_NPU_CM0_RTC			249
+#define HCLK_RKNN_CBUF			250
+#define HCLK_NVM_ROOT			251
+#define ACLK_NVM_ROOT			252
+#define SCLK_FSPI_X2			253
+#define HCLK_FSPI			254
+#define CCLK_SRC_EMMC			255
+#define HCLK_EMMC			256
+#define ACLK_EMMC			257
+#define BCLK_EMMC			258
+#define TCLK_EMMC			259
+#define PCLK_PHP_ROOT			260
+#define ACLK_PHP_ROOT			261
+#define PCLK_PCIE0			262
+#define CLK_PCIE0_AUX			263
+#define ACLK_PCIE0_MST			264
+#define ACLK_PCIE0_SLV			265
+#define ACLK_PCIE0_DBI			266
+#define ACLK_USB3OTG1			267
+#define CLK_REF_USB3OTG1		268
+#define CLK_SUSPEND_USB3OTG1		269
+#define ACLK_MMU0			270
+#define ACLK_SLV_MMU0			271
+#define ACLK_MMU1			272
+#define ACLK_SLV_MMU1			273
+#define PCLK_PCIE1			275
+#define CLK_PCIE1_AUX			276
+#define ACLK_PCIE1_MST			277
+#define ACLK_PCIE1_SLV			278
+#define ACLK_PCIE1_DBI			279
+#define CLK_RXOOB0			280
+#define CLK_RXOOB1			281
+#define CLK_PMALIVE0			282
+#define CLK_PMALIVE1			283
+#define ACLK_SATA0			284
+#define ACLK_SATA1			285
+#define CLK_USB3OTG1_PIPE_PCLK		286
+#define CLK_USB3OTG1_UTMI		287
+#define CLK_USB3OTG0_PIPE_PCLK		288
+#define CLK_USB3OTG0_UTMI		289
+#define HCLK_SDGMAC_ROOT		290
+#define ACLK_SDGMAC_ROOT		291
+#define PCLK_SDGMAC_ROOT		292
+#define ACLK_GMAC0			293
+#define ACLK_GMAC1			294
+#define PCLK_GMAC0			295
+#define PCLK_GMAC1			296
+#define CCLK_SRC_SDIO			297
+#define HCLK_SDIO			298
+#define CLK_GMAC1_PTP_REF		299
+#define CLK_GMAC0_PTP_REF		300
+#define CLK_GMAC1_PTP_REF_SRC		301
+#define CLK_GMAC0_PTP_REF_SRC		302
+#define CCLK_SRC_SDMMC0			303
+#define HCLK_SDMMC0			304
+#define SCLK_FSPI1_X2			305
+#define HCLK_FSPI1			306
+#define ACLK_DSMC_ROOT			307
+#define ACLK_DSMC			308
+#define PCLK_DSMC			309
+#define CLK_DSMC_SYS			310
+#define HCLK_HSGPIO			311
+#define CLK_HSGPIO_TX			312
+#define CLK_HSGPIO_RX			313
+#define ACLK_HSGPIO			314
+#define PCLK_PHPPHY_ROOT		315
+#define PCLK_PCIE2_COMBOPHY0		316
+#define PCLK_PCIE2_COMBOPHY1		317
+#define CLK_PCIE_100M_SRC		318
+#define CLK_PCIE_100M_NDUTY_SRC		319
+#define CLK_REF_PCIE0_PHY		320
+#define CLK_REF_PCIE1_PHY		321
+#define CLK_REF_MPHY_26M		322
+#define HCLK_RKVDEC_ROOT		323
+#define ACLK_RKVDEC_ROOT		324
+#define HCLK_RKVDEC			325
+#define CLK_RKVDEC_HEVC_CA		326
+#define CLK_RKVDEC_CORE			327
+#define ACLK_UFS_ROOT			328
+#define ACLK_USB_ROOT			329
+#define PCLK_USB_ROOT			330
+#define ACLK_USB3OTG0			331
+#define CLK_REF_USB3OTG0		332
+#define CLK_SUSPEND_USB3OTG0		333
+#define ACLK_MMU2			334
+#define ACLK_SLV_MMU2			335
+#define ACLK_UFS_SYS			336
+#define ACLK_VPU_ROOT			337
+#define ACLK_VPU_MID_ROOT		338
+#define HCLK_VPU_ROOT			339
+#define ACLK_JPEG_ROOT			340
+#define ACLK_VPU_LOW_ROOT		341
+#define HCLK_RGA2E_0			342
+#define ACLK_RGA2E_0			342
+#define CLK_CORE_RGA2E_0		344
+#define ACLK_JPEG			345
+#define HCLK_JPEG			346
+#define HCLK_VDPP			347
+#define ACLK_VDPP			348
+#define CLK_CORE_VDPP			349
+#define HCLK_RGA2E_1			350
+#define ACLK_RGA2E_1			351
+#define CLK_CORE_RGA2E_1		352
+#define DCLK_EBC_FRAC_SRC		353
+#define HCLK_EBC			354
+#define ACLK_EBC			355
+#define DCLK_EBC			356
+#define HCLK_VEPU0_ROOT			357
+#define ACLK_VEPU0_ROOT			358
+#define HCLK_VEPU0			359
+#define ACLK_VEPU0			360
+#define CLK_VEPU0_CORE			361
+#define ACLK_VI_ROOT			362
+#define HCLK_VI_ROOT			363
+#define PCLK_VI_ROOT			364
+#define DCLK_VICAP			365
+#define ACLK_VICAP			366
+#define HCLK_VICAP			367
+#define CLK_ISP_CORE			368
+#define CLK_ISP_CORE_MARVIN		369
+#define CLK_ISP_CORE_VICAP		370
+#define ACLK_ISP			371
+#define HCLK_ISP			372
+#define ACLK_VPSS			373
+#define HCLK_VPSS			374
+#define CLK_CORE_VPSS			375
+#define PCLK_CSI_HOST_0			376
+#define PCLK_CSI_HOST_1			377
+#define PCLK_CSI_HOST_2			378
+#define PCLK_CSI_HOST_3			379
+#define PCLK_CSI_HOST_4			380
+#define ICLK_CSIHOST01			381
+#define ICLK_CSIHOST0			382
+#define CLK_ISP_PVTPLL_SRC		383
+#define ACLK_VI_ROOT_INTER		384
+#define CLK_VICAP_I0CLK			385
+#define CLK_VICAP_I1CLK			386
+#define CLK_VICAP_I2CLK			387
+#define CLK_VICAP_I3CLK			388
+#define CLK_VICAP_I4CLK			389
+#define ACLK_VOP_ROOT			390
+#define HCLK_VOP_ROOT			391
+#define PCLK_VOP_ROOT			392
+#define HCLK_VOP			393
+#define ACLK_VOP			394
+#define DCLK_VP0_SRC			395
+#define DCLK_VP1_SRC			396
+#define DCLK_VP2_SRC			397
+#define DCLK_VP0			398
+#define DCLK_VP1			400
+#define DCLK_VP2			401
+#define PCLK_VOPGRF			402
+#define ACLK_VO0_ROOT			403
+#define HCLK_VO0_ROOT			404
+#define PCLK_VO0_ROOT			405
+#define PCLK_VO0_GRF			406
+#define ACLK_HDCP0			407
+#define HCLK_HDCP0			408
+#define PCLK_HDCP0			409
+#define CLK_TRNG0_SKP			410
+#define PCLK_DSIHOST0			411
+#define CLK_DSIHOST0			412
+#define PCLK_HDMITX0			413
+#define CLK_HDMITX0_EARC		414
+#define CLK_HDMITX0_REF			415
+#define PCLK_EDP0			416
+#define CLK_EDP0_24M			417
+#define CLK_EDP0_200M			418
+#define MCLK_SAI5_8CH_SRC		419
+#define MCLK_SAI5_8CH			420
+#define HCLK_SAI5_8CH			421
+#define MCLK_SAI6_8CH_SRC		422
+#define MCLK_SAI6_8CH			423
+#define HCLK_SAI6_8CH			424
+#define HCLK_SPDIF_TX2			425
+#define MCLK_SPDIF_TX2			426
+#define HCLK_SPDIF_RX2			427
+#define MCLK_SPDIF_RX2			428
+#define HCLK_SAI8_8CH			429
+#define MCLK_SAI8_8CH_SRC		430
+#define MCLK_SAI8_8CH			431
+#define ACLK_VO1_ROOT			432
+#define HCLK_VO1_ROOT			433
+#define PCLK_VO1_ROOT			434
+#define MCLK_SAI7_8CH_SRC		435
+#define MCLK_SAI7_8CH			436
+#define HCLK_SAI7_8CH			437
+#define HCLK_SPDIF_TX3			438
+#define HCLK_SPDIF_TX4			439
+#define HCLK_SPDIF_TX5			440
+#define MCLK_SPDIF_TX3			441
+#define CLK_AUX16MHZ_0			442
+#define ACLK_DP0			443
+#define PCLK_DP0			444
+#define PCLK_VO1_GRF			445
+#define ACLK_HDCP1			446
+#define HCLK_HDCP1			447
+#define PCLK_HDCP1			448
+#define CLK_TRNG1_SKP			449
+#define HCLK_SAI9_8CH			450
+#define MCLK_SAI9_8CH_SRC		451
+#define MCLK_SAI9_8CH			452
+#define MCLK_SPDIF_TX4			453
+#define MCLK_SPDIF_TX5			454
+#define CLK_GPU_SRC_PRE			455
+#define CLK_GPU				456
+#define PCLK_GPU_ROOT			457
+#define ACLK_CENTER_ROOT		458
+#define ACLK_CENTER_LOW_ROOT		459
+#define HCLK_CENTER_ROOT		460
+#define PCLK_CENTER_ROOT		461
+#define ACLK_DMA2DDR			462
+#define ACLK_DDR_SHAREMEM		463
+#define PCLK_DMA2DDR			464
+#define PCLK_SHAREMEM			465
+#define HCLK_VEPU1_ROOT			466
+#define ACLK_VEPU1_ROOT			467
+#define HCLK_VEPU1			468
+#define ACLK_VEPU1			469
+#define CLK_VEPU1_CORE			470
+#define CLK_JDBCK_DAP			471
+#define PCLK_MIPI_DCPHY			472
+#define CLK_32K_USB2DEBUG		473
+#define PCLK_CSIDPHY			474
+#define PCLK_USBDPPHY			475
+#define CLK_PMUPHY_REF_SRC		476
+#define CLK_USBDP_COMBO_PHY_IMMORTAL	477
+#define CLK_HDMITXHPD			478
+#define PCLK_MPHY			479
+#define CLK_REF_OSC_MPHY		480
+#define CLK_REF_UFS_CLKOUT		481
+#define HCLK_PMU1_ROOT			482
+#define HCLK_PMU_CM0_ROOT		483
+#define CLK_200M_PMU_SRC		484
+#define CLK_100M_PMU_SRC		485
+#define CLK_50M_PMU_SRC			486
+#define FCLK_PMU_CM0_CORE		487
+#define CLK_PMU_CM0_RTC			488
+#define PCLK_PMU1			489
+#define CLK_PMU1			490
+#define PCLK_PMU1WDT			491
+#define TCLK_PMU1WDT			492
+#define PCLK_PMUTIMER			493
+#define CLK_PMUTIMER_ROOT		494
+#define CLK_PMUTIMER0			495
+#define CLK_PMUTIMER1			496
+#define PCLK_PMU1PWM			497
+#define CLK_PMU1PWM			498
+#define CLK_PMU1PWM_OSC			499
+#define PCLK_PMUPHY_ROOT		500
+#define PCLK_I2C0			501
+#define CLK_I2C0			502
+#define SCLK_UART1			503
+#define PCLK_UART1			504
+#define CLK_PMU1PWM_RC			505
+#define CLK_PDM0			506
+#define HCLK_PDM0			507
+#define MCLK_PDM0			508
+#define HCLK_VAD			509
+#define CLK_OSCCHK_PVTM			510
+#define CLK_PDM0_OUT			511
+#define CLK_HPTIMER_SRC			512
+#define PCLK_PMU0_ROOT			516
+#define PCLK_PMU0			517
+#define PCLK_GPIO0			518
+#define DBCLK_GPIO0			519
+#define CLK_OSC0_PMU1			520
+#define PCLK_PMU1_ROOT			521
+#define XIN_OSC0_DIV			522
+#define ACLK_USB			523
+#define ACLK_UFS			524
+#define ACLK_SDGMAC			525
+#define HCLK_SDGMAC			526
+#define PCLK_SDGMAC			527
+#define HCLK_VO1			528
+#define HCLK_VO0			529
+#define PCLK_CCI_ROOT			532
+#define ACLK_CCI_ROOT			533
+#define HCLK_VO0VOP_CHANNEL		534
+#define ACLK_VO0VOP_CHANNEL		535
+#define ACLK_TOP_MID			536
+#define ACLK_SECURE_HIGH		537
+#define CLK_USBPHY_REF_SRC		538
+#define CLK_PHY_REF_SRC			539
+#define CLK_CPLL_REF_SRC		540
+#define CLK_AUPLL_REF_SRC		541
+#define PCLK_SECURE_NS			542
+#define HCLK_SECURE_NS			543
+#define ACLK_SECURE_NS			544
+#define PCLK_OTPC_NS			545
+#define HCLK_CRYPTO_NS			546
+#define HCLK_TRNG_NS			547
+#define CLK_OTPC_NS			548
+#define SCLK_DSU			549
+#define SCLK_DDR			550
+#define ACLK_CRYPTO_NS			551
+#define CLK_PKA_CRYPTO_NS		552
+
+/* secure clk */
+#define CLK_STIMER0_ROOT		600
+#define CLK_STIMER1_ROOT		601
+#define PCLK_SECURE_S			602
+#define HCLK_SECURE_S			603
+#define ACLK_SECURE_S			604
+#define CLK_PKA_CRYPTO_S		605
+#define HCLK_VO1_S			606
+#define PCLK_VO1_S			607
+#define HCLK_VO0_S			608
+#define PCLK_VO0_S			609
+#define PCLK_KLAD			610
+#define HCLK_CRYPTO_S			611
+#define HCLK_KLAD			612
+#define ACLK_CRYPTO_S			613
+#define HCLK_TRNG_S			614
+#define PCLK_OTPC_S			615
+#define CLK_OTPC_S			616
+#define PCLK_WDT_S			617
+#define TCLK_WDT_S			618
+#define PCLK_HDCP0_TRNG			619
+#define PCLK_HDCP1_TRNG			620
+#define HCLK_HDCP_KEY0			621
+#define HCLK_HDCP_KEY1			622
+#define PCLK_EDP_S			623
+#define ACLK_KLAD			624
+
+#define CLK_NR_CLKS			(ACLK_KLAD + 1)
+
+/********Name=SOFTRST_CON01,Offset=0xA04********/
+#define SRST_A_TOP_BIU			19
+#define SRST_P_TOP_BIU			21
+#define SRST_A_TOP_MID_BIU		22
+#define SRST_A_SECURE_HIGH_BIU		23
+#define SRST_H_TOP_BIU			30
+/********Name=SOFTRST_CON02,Offset=0xA08********/
+#define SRST_H_VO0VOP_CHANNEL_BIU	32
+#define SRST_A_VO0VOP_CHANNEL_BIU	33
+/********Name=SOFTRST_CON06,Offset=0xA18********/
+#define SRST_BISRINTF			98
+/********Name=SOFTRST_CON07,Offset=0xA1C********/
+#define SRST_H_AUDIO_BIU		114
+#define SRST_H_ASRC_2CH_0		115
+#define SRST_H_ASRC_2CH_1		116
+#define SRST_H_ASRC_4CH_0		117
+#define SRST_H_ASRC_4CH_1		118
+#define SRST_ASRC_2CH_0			119
+#define SRST_ASRC_2CH_1			120
+#define SRST_ASRC_4CH_0			121
+#define SRST_ASRC_4CH_1			122
+#define SRST_M_SAI0_8CH			124
+#define SRST_H_SAI0_8CH			125
+#define SRST_H_SPDIF_RX0		126
+#define SRST_M_SPDIF_RX0		127
+/********Name=SOFTRST_CON08,Offset=0xA20********/
+#define SRST_H_SPDIF_RX1		128
+#define SRST_M_SPDIF_RX1		129
+#define SRST_M_SAI1_8CH			133
+#define SRST_H_SAI1_8CH			134
+#define SRST_M_SAI2_2CH			136
+#define SRST_H_SAI2_2CH			138
+#define SRST_M_SAI3_2CH			140
+#define SRST_H_SAI3_2CH			142
+/********Name=SOFTRST_CON09,Offset=0xA24********/
+#define SRST_M_SAI4_2CH			144
+#define SRST_H_SAI4_2CH			146
+#define SRST_H_ACDCDIG_DSM		147
+#define SRST_M_ACDCDIG_DSM		148
+#define SRST_PDM1			149
+#define SRST_H_PDM1			151
+#define SRST_M_PDM1			152
+#define SRST_H_SPDIF_TX0		153
+#define SRST_M_SPDIF_TX0		154
+#define SRST_H_SPDIF_TX1		155
+#define SRST_M_SPDIF_TX1		156
+/********Name=SOFTRST_CON11,Offset=0xA2C********/
+#define SRST_A_BUS_BIU			179
+#define SRST_P_BUS_BIU			180
+#define SRST_P_CRU			181
+#define SRST_H_CAN0			182
+#define SRST_CAN0			183
+#define SRST_H_CAN1			184
+#define SRST_CAN1			185
+#define SRST_P_INTMUX2BUS		188
+#define SRST_P_VCCIO_IOC		189
+#define SRST_H_BUS_BIU			190
+#define SRST_KEY_SHIFT			191
+/********Name=SOFTRST_CON12,Offset=0xA30********/
+#define SRST_P_I2C1			192
+#define SRST_P_I2C2			193
+#define SRST_P_I2C3			194
+#define SRST_P_I2C4			195
+#define SRST_P_I2C5			196
+#define SRST_P_I2C6			197
+#define SRST_P_I2C7			198
+#define SRST_P_I2C8			199
+#define SRST_P_I2C9			200
+#define SRST_P_WDT_BUSMCU		201
+#define SRST_T_WDT_BUSMCU		202
+#define SRST_A_GIC			203
+#define SRST_I2C1			204
+#define SRST_I2C2			205
+#define SRST_I2C3			206
+#define SRST_I2C4			207
+/********Name=SOFTRST_CON13,Offset=0xA34********/
+#define SRST_I2C5			208
+#define SRST_I2C6			209
+#define SRST_I2C7			210
+#define SRST_I2C8			211
+#define SRST_I2C9			212
+#define SRST_P_SARADC			214
+#define SRST_SARADC			215
+#define SRST_P_TSADC			216
+#define SRST_TSADC			217
+#define SRST_P_UART0			218
+#define SRST_P_UART2			219
+#define SRST_P_UART3			220
+#define SRST_P_UART4			221
+#define SRST_P_UART5			222
+#define SRST_P_UART6			223
+/********Name=SOFTRST_CON14,Offset=0xA38********/
+#define SRST_P_UART7			224
+#define SRST_P_UART8			225
+#define SRST_P_UART9			226
+#define SRST_P_UART10			227
+#define SRST_P_UART11			228
+#define SRST_S_UART0			229
+#define SRST_S_UART2			230
+#define SRST_S_UART3			233
+#define SRST_S_UART4			236
+#define SRST_S_UART5			239
+/********Name=SOFTRST_CON15,Offset=0xA3C********/
+#define SRST_S_UART6			242
+#define SRST_S_UART7			245
+#define SRST_S_UART8			248
+#define SRST_S_UART9			249
+#define SRST_S_UART10			250
+#define SRST_S_UART11			251
+#define SRST_P_SPI0			253
+#define SRST_P_SPI1			254
+#define SRST_P_SPI2			255
+/********Name=SOFTRST_CON16,Offset=0xA40********/
+#define SRST_P_SPI3			256
+#define SRST_P_SPI4			257
+#define SRST_SPI0			258
+#define SRST_SPI1			259
+#define SRST_SPI2			260
+#define SRST_SPI3			261
+#define SRST_SPI4			262
+#define SRST_P_WDT0			263
+#define SRST_T_WDT0			264
+#define SRST_P_SYS_GRF			265
+#define SRST_P_PWM1			266
+#define SRST_PWM1			267
+
+/********Name=SOFTRST_CON17,Offset=0xA44********/
+#define SRST_P_BUSTIMER0		275
+#define SRST_P_BUSTIMER1		276
+#define SRST_TIMER0			278
+#define SRST_TIMER1			279
+#define SRST_TIMER2			280
+#define SRST_TIMER3			281
+#define SRST_TIMER4			282
+#define SRST_TIMER5			283
+#define SRST_P_BUSIOC			284
+#define SRST_P_MAILBOX0			285
+#define SRST_P_GPIO1			287
+/********Name=SOFTRST_CON18,Offset=0xA48********/
+#define SRST_GPIO1			288
+#define SRST_P_GPIO2			289
+#define SRST_GPIO2			290
+#define SRST_P_GPIO3			291
+#define SRST_GPIO3			292
+#define SRST_P_GPIO4			293
+#define SRST_GPIO4			294
+#define SRST_A_DECOM			295
+#define SRST_P_DECOM			296
+#define SRST_D_DECOM			297
+#define SRST_TIMER6			299
+#define SRST_TIMER7			300
+#define SRST_TIMER8			301
+#define SRST_TIMER9			302
+#define SRST_TIMER10			303
+/********Name=SOFTRST_CON19,Offset=0xA4C********/
+#define SRST_TIMER11			304
+#define SRST_A_DMAC0			305
+#define SRST_A_DMAC1			306
+#define SRST_A_DMAC2			307
+#define SRST_A_SPINLOCK			308
+#define SRST_REF_PVTPLL_BUS		309
+#define SRST_H_I3C0			311
+#define SRST_H_I3C1			313
+#define SRST_H_BUS_CM0_BIU		315
+#define SRST_F_BUS_CM0_CORE		316
+#define SRST_T_BUS_CM0_JTAG		317
+/********Name=SOFTRST_CON20,Offset=0xA50********/
+#define SRST_P_INTMUX2PMU		320
+#define SRST_P_INTMUX2DDR		321
+#define SRST_P_PVTPLL_BUS		323
+#define SRST_P_PWM2			324
+#define SRST_PWM2			325
+#define SRST_FREQ_PWM1			328
+#define SRST_COUNTER_PWM1		329
+#define SRST_I3C0			332
+#define SRST_I3C1			333
+/********Name=SOFTRST_CON21,Offset=0xA54********/
+#define SRST_P_DDR_MON_CH0		337
+#define SRST_P_DDR_BIU			338
+#define SRST_P_DDR_UPCTL_CH0		339
+#define SRST_TM_DDR_MON_CH0		340
+#define SRST_A_DDR_BIU			341
+#define SRST_DFI_CH0			342
+#define SRST_DDR_MON_CH0		346
+#define SRST_P_DDR_HWLP_CH0		349
+#define SRST_P_DDR_MON_CH1		350
+#define SRST_P_DDR_HWLP_CH1		351
+/********Name=SOFTRST_CON22,Offset=0xA58********/
+#define SRST_P_DDR_UPCTL_CH1		352
+#define SRST_TM_DDR_MON_CH1		353
+#define SRST_DFI_CH1			354
+#define SRST_A_DDR01_MSCH0		355
+#define SRST_A_DDR01_MSCH1		356
+#define SRST_DDR_MON_CH1		358
+#define SRST_DDR_SCRAMBLE_CH0		361
+#define SRST_DDR_SCRAMBLE_CH1		362
+#define SRST_P_AHB2APB			364
+#define SRST_H_AHB2APB			365
+#define SRST_H_DDR_BIU			366
+#define SRST_F_DDR_CM0_CORE		367
+/********Name=SOFTRST_CON23,Offset=0xA5C********/
+#define SRST_P_DDR01_MSCH0		369
+#define SRST_P_DDR01_MSCH1		370
+#define SRST_DDR_TIMER0			372
+#define SRST_DDR_TIMER1			373
+#define SRST_T_WDT_DDR			374
+#define SRST_P_WDT			375
+#define SRST_P_TIMER			376
+#define SRST_T_DDR_CM0_JTAG		377
+#define SRST_P_DDR_GRF			379
+/********Name=SOFTRST_CON25,Offset=0xA64********/
+#define SRST_DDR_UPCTL_CH0		401
+#define SRST_A_DDR_UPCTL_0_CH0		402
+#define SRST_A_DDR_UPCTL_1_CH0		403
+#define SRST_A_DDR_UPCTL_2_CH0		404
+#define SRST_A_DDR_UPCTL_3_CH0		405
+#define SRST_A_DDR_UPCTL_4_CH0		406
+/********Name=SOFTRST_CON26,Offset=0xA68********/
+#define SRST_DDR_UPCTL_CH1		417
+#define SRST_A_DDR_UPCTL_0_CH1		418
+#define SRST_A_DDR_UPCTL_1_CH1		419
+#define SRST_A_DDR_UPCTL_2_CH1		420
+#define SRST_A_DDR_UPCTL_3_CH1		421
+#define SRST_A_DDR_UPCTL_4_CH1		422
+/********Name=SOFTRST_CON27,Offset=0xA6C********/
+#define SRST_REF_PVTPLL_DDR		432
+#define SRST_P_PVTPLL_DDR		433
+
+/********Name=SOFTRST_CON28,Offset=0xA70********/
+#define SRST_A_RKNN0			457
+#define SRST_A_RKNN0_BIU		459
+#define SRST_L_RKNN0_BIU		460
+/********Name=SOFTRST_CON29,Offset=0xA74********/
+#define SRST_A_RKNN1			464
+#define SRST_A_RKNN1_BIU		466
+#define SRST_L_RKNN1_BIU		467
+/********Name=SOFTRST_CON31,Offset=0xA7C********/
+#define SRST_NPU_DAP			496
+#define SRST_L_NPUSUBSYS_BIU		497
+#define SRST_P_NPUTOP_BIU		505
+#define SRST_P_NPU_TIMER		506
+#define SRST_NPUTIMER0			508
+#define SRST_NPUTIMER1			509
+#define SRST_P_NPU_WDT			510
+#define SRST_T_NPU_WDT			511
+/********Name=SOFTRST_CON32,Offset=0xA80********/
+#define SRST_A_RKNN_CBUF		512
+#define SRST_A_RVCORE0			513
+#define SRST_P_NPU_GRF			514
+#define SRST_P_PVTPLL_NPU		515
+#define SRST_NPU_PVTPLL			516
+#define SRST_H_NPU_CM0_BIU		518
+#define SRST_F_NPU_CM0_CORE		519
+#define SRST_T_NPU_CM0_JTAG		520
+#define SRST_A_RKNNTOP_BIU		523
+#define SRST_H_RKNN_CBUF		524
+#define SRST_H_RKNNTOP_BIU		525
+/********Name=SOFTRST_CON33,Offset=0xA84********/
+#define SRST_H_NVM_BIU			530
+#define SRST_A_NVM_BIU			531
+#define SRST_S_FSPI			534
+#define SRST_H_FSPI			535
+#define SRST_C_EMMC			536
+#define SRST_H_EMMC			537
+#define SRST_A_EMMC			538
+#define SRST_B_EMMC			539
+#define SRST_T_EMMC			540
+/********Name=SOFTRST_CON34,Offset=0xA88********/
+#define SRST_P_GRF			545
+#define SRST_P_PHP_BIU			549
+#define SRST_A_PHP_BIU			553
+#define SRST_P_PCIE0			557
+#define SRST_PCIE0_POWER_UP		559
+/********Name=SOFTRST_CON35,Offset=0xA8C********/
+#define SRST_A_USB3OTG1			563
+#define SRST_A_MMU0			571
+#define SRST_A_SLV_MMU0			573
+#define SRST_A_MMU1			574
+/********Name=SOFTRST_CON36,Offset=0xA90********/
+#define SRST_A_SLV_MMU1			576
+#define SRST_P_PCIE1			583
+#define SRST_PCIE1_POWER_UP		585
+/********Name=SOFTRST_CON37,Offset=0xA94********/
+#define SRST_RXOOB0			592
+#define SRST_RXOOB1			593
+#define SRST_PMALIVE0			594
+#define SRST_PMALIVE1			595
+#define SRST_A_SATA0			596
+#define SRST_A_SATA1			597
+#define SRST_ASIC1			598
+#define SRST_ASIC0			599
+/********Name=SOFTRST_CON40,Offset=0xAA0********/
+#define SRST_P_CSIDPHY1			642
+#define SRST_SCAN_CSIDPHY1		643
+/********Name=SOFTRST_CON42,Offset=0xAA8********/
+#define SRST_P_SDGMAC_GRF		675
+#define SRST_P_SDGMAC_BIU		676
+#define SRST_A_SDGMAC_BIU		677
+#define SRST_H_SDGMAC_BIU		678
+#define SRST_A_GMAC0			679
+#define SRST_A_GMAC1			680
+#define SRST_P_GMAC0			681
+#define SRST_P_GMAC1			682
+#define SRST_H_SDIO			684
+/********Name=SOFTRST_CON43,Offset=0xAAC********/
+#define SRST_H_SDMMC0			690
+#define SRST_S_FSPI1			691
+#define SRST_H_FSPI1			692
+#define SRST_A_DSMC_BIU			694
+#define SRST_A_DSMC			695
+#define SRST_P_DSMC			696
+#define SRST_H_HSGPIO			698
+#define SRST_HSGPIO			699
+#define SRST_A_HSGPIO			701
+/********Name=SOFTRST_CON45,Offset=0xAB4********/
+#define SRST_H_RKVDEC			723
+#define SRST_H_RKVDEC_BIU		725
+#define SRST_A_RKVDEC_BIU		726
+#define SRST_RKVDEC_HEVC_CA		728
+#define SRST_RKVDEC_CORE		729
+/********Name=SOFTRST_CON47,Offset=0xABC********/
+#define SRST_A_USB_BIU			755
+#define SRST_P_USBUFS_BIU		756
+#define SRST_A_USB3OTG0			757
+#define SRST_A_UFS_BIU			762
+#define SRST_A_MMU2			764
+#define SRST_A_SLV_MMU2			765
+#define SRST_A_UFS_SYS			767
+/********Name=SOFTRST_CON48,Offset=0xAC0********/
+#define SRST_A_UFS			768
+#define SRST_P_USBUFS_GRF		769
+#define SRST_P_UFS_GRF			770
+/********Name=SOFTRST_CON49,Offset=0xAC4********/
+#define SRST_H_VPU_BIU			790
+#define SRST_A_JPEG_BIU			791
+#define SRST_A_RGA_BIU			794
+#define SRST_A_VDPP_BIU			795
+#define SRST_A_EBC_BIU			796
+#define SRST_H_RGA2E_0			797
+#define SRST_A_RGA2E_0			798
+#define SRST_CORE_RGA2E_0		799
+/********Name=SOFTRST_CON50,Offset=0xAC8********/
+#define SRST_A_JPEG			800
+#define SRST_H_JPEG			801
+#define SRST_H_VDPP			802
+#define SRST_A_VDPP			803
+#define SRST_CORE_VDPP			804
+#define SRST_H_RGA2E_1			805
+#define SRST_A_RGA2E_1			806
+#define SRST_CORE_RGA2E_1		807
+#define SRST_H_EBC			810
+#define SRST_A_EBC			811
+#define SRST_D_EBC			812
+/********Name=SOFTRST_CON51,Offset=0xACC********/
+#define SRST_H_VEPU0_BIU		818
+#define SRST_A_VEPU0_BIU		819
+#define SRST_H_VEPU0			820
+#define SRST_A_VEPU0			821
+#define SRST_VEPU0_CORE			822
+/********Name=SOFTRST_CON53,Offset=0xAD4********/
+#define SRST_A_VI_BIU			851
+#define SRST_H_VI_BIU			852
+#define SRST_P_VI_BIU			853
+#define SRST_D_VICAP			854
+#define SRST_A_VICAP			855
+#define SRST_H_VICAP			856
+#define SRST_ISP0			858
+#define SRST_ISP0_VICAP			859
+/********Name=SOFTRST_CON54,Offset=0xAD8********/
+#define SRST_CORE_VPSS			865
+#define SRST_P_CSI_HOST_0		868
+#define SRST_P_CSI_HOST_1		869
+#define SRST_P_CSI_HOST_2		870
+#define SRST_P_CSI_HOST_3		871
+#define SRST_P_CSI_HOST_4		872
+/********Name=SOFTRST_CON59,Offset=0xAEC********/
+#define SRST_CIFIN			944
+#define SRST_VICAP_I0CLK		945
+#define SRST_VICAP_I1CLK		946
+#define SRST_VICAP_I2CLK		947
+#define SRST_VICAP_I3CLK		948
+#define SRST_VICAP_I4CLK		949
+/********Name=SOFTRST_CON61,Offset=0xAF4********/
+#define SRST_A_VOP_BIU			980
+#define SRST_A_VOP2_BIU			981
+#define SRST_H_VOP_BIU			982
+#define SRST_P_VOP_BIU			983
+#define SRST_H_VOP			984
+#define SRST_A_VOP			985
+#define SRST_D_VP0			989
+/********Name=SOFTRST_CON62,Offset=0xAF8********/
+#define SRST_D_VP1			992
+#define SRST_D_VP2			993
+#define SRST_P_VOP2_BIU			994
+#define SRST_P_VOPGRF			995
+/********Name=SOFTRST_CON63,Offset=0xAFC********/
+#define SRST_H_VO0_BIU			1013
+#define SRST_P_VO0_BIU			1015
+#define SRST_A_HDCP0_BIU		1017
+#define SRST_P_VO0_GRF			1018
+#define SRST_A_HDCP0			1020
+#define SRST_H_HDCP0			1021
+#define SRST_HDCP0			1022
+/********Name=SOFTRST_CON64,Offset=0xB00********/
+#define SRST_P_DSIHOST0			1029
+#define SRST_DSIHOST0			1030
+#define SRST_P_HDMITX0			1031
+#define SRST_HDMITX0_REF		1033
+#define SRST_P_EDP0			1037
+#define SRST_EDP0_24M			1038
+/********Name=SOFTRST_CON65,Offset=0xB04********/
+#define SRST_M_SAI5_8CH			1044
+#define SRST_H_SAI5_8CH			1045
+#define SRST_M_SAI6_8CH			1048
+#define SRST_H_SAI6_8CH			1049
+#define SRST_H_SPDIF_TX2		1050
+#define SRST_M_SPDIF_TX2		1053
+#define SRST_H_SPDIF_RX2		1054
+#define SRST_M_SPDIF_RX2		1055
+/********Name=SOFTRST_CON66,Offset=0xB08********/
+#define SRST_H_SAI8_8CH			1056
+#define SRST_M_SAI8_8CH			1058
+/********Name=SOFTRST_CON67,Offset=0xB0C********/
+#define SRST_H_VO1_BIU			1077
+#define SRST_P_VO1_BIU			1078
+#define SRST_M_SAI7_8CH			1081
+#define SRST_H_SAI7_8CH			1082
+#define SRST_H_SPDIF_TX3		1083
+#define SRST_H_SPDIF_TX4		1084
+#define SRST_H_SPDIF_TX5		1085
+#define SRST_M_SPDIF_TX3		1086
+/********Name=SOFTRST_CON68,Offset=0xB10********/
+#define SRST_DP0			1088
+#define SRST_P_VO1_GRF			1090
+#define SRST_A_HDCP1_BIU		1091
+#define SRST_A_HDCP1			1092
+#define SRST_H_HDCP1			1093
+#define SRST_HDCP1			1094
+#define SRST_H_SAI9_8CH			1097
+#define SRST_M_SAI9_8CH			1099
+#define SRST_M_SPDIF_TX4		1100
+#define SRST_M_SPDIF_TX5		1101
+/********Name=SOFTRST_CON69,Offset=0xB14********/
+#define SRST_GPU			1107
+#define SRST_A_S_GPU_BIU		1110
+#define SRST_A_M0_GPU_BIU		1111
+#define SRST_P_GPU_BIU			1113
+#define SRST_P_GPU_GRF			1117
+#define SRST_GPU_PVTPLL			1118
+#define SRST_P_PVTPLL_GPU		1119
+/********Name=SOFTRST_CON72,Offset=0xB20********/
+#define SRST_A_CENTER_BIU		1156
+#define SRST_A_DMA2DDR			1157
+#define SRST_A_DDR_SHAREMEM		1158
+#define SRST_A_DDR_SHAREMEM_BIU		1159
+#define SRST_H_CENTER_BIU		1160
+#define SRST_P_CENTER_GRF		1161
+#define SRST_P_DMA2DDR			1162
+#define SRST_P_SHAREMEM			1163
+#define SRST_P_CENTER_BIU		1164
+/********Name=SOFTRST_CON75,Offset=0xB2C********/
+#define SRST_LINKSYM_HDMITXPHY0		1201
+/********Name=SOFTRST_CON78,Offset=0xB38********/
+#define SRST_DP0_PIXELCLK		1249
+#define SRST_PHY_DP0_TX			1250
+#define SRST_DP1_PIXELCLK		1251
+#define SRST_DP2_PIXELCLK		1252
+/********Name=SOFTRST_CON79,Offset=0xB3C********/
+#define SRST_H_VEPU1_BIU		1265
+#define SRST_A_VEPU1_BIU		1266
+#define SRST_H_VEPU1			1267
+#define SRST_A_VEPU1			1268
+#define SRST_VEPU1_CORE			1269
+
+/********Name=PHPPHYSOFTRST_CON00,Offset=0x8A00********/
+#define SRST_P_PHPPHY_CRU		131073
+#define SRST_P_APB2ASB_SLV_CHIP_TOP	131075
+#define SRST_P_PCIE2_COMBOPHY0		131077
+#define SRST_P_PCIE2_COMBOPHY0_GRF	131078
+#define SRST_P_PCIE2_COMBOPHY1		131079
+#define SRST_P_PCIE2_COMBOPHY1_GRF	131080
+/********Name=PHPPHYSOFTRST_CON01,Offset=0x8A04********/
+#define SRST_PCIE0_PIPE_PHY		131093
+#define SRST_PCIE1_PIPE_PHY		131096
+
+/********Name=SECURENSSOFTRST_CON00,Offset=0x10A00********/
+#define SRST_H_CRYPTO_NS		262147
+#define SRST_H_TRNG_NS			262148
+#define SRST_P_OTPC_NS			262152
+#define SRST_OTPC_NS			262153
+
+/********Name=PMU1SOFTRST_CON00,Offset=0x20A00********/
+#define SRST_P_HDPTX_GRF		524288
+#define SRST_P_HDPTX_APB		524289
+#define SRST_P_MIPI_DCPHY		524290
+#define SRST_P_DCPHY_GRF		524291
+#define SRST_P_BOT0_APB2ASB		524292
+#define SRST_P_BOT1_APB2ASB		524293
+#define SRST_USB2DEBUG			524294
+#define SRST_P_CSIPHY_GRF		524295
+#define SRST_P_CSIPHY			524296
+#define SRST_P_USBPHY_GRF_0		524297
+#define SRST_P_USBPHY_GRF_1		524298
+#define SRST_P_USBDP_GRF		524299
+#define SRST_P_USBDPPHY			524300
+#define SRST_USBDP_COMBO_PHY_INIT 524303
+/********Name=PMU1SOFTRST_CON01,Offset=0x20A04********/
+#define SRST_USBDP_COMBO_PHY_CMN	524304
+#define SRST_USBDP_COMBO_PHY_LANE	524305
+#define SRST_USBDP_COMBO_PHY_PCS	524306
+#define SRST_M_MIPI_DCPHY		524307
+#define SRST_S_MIPI_DCPHY		524308
+#define SRST_SCAN_CSIPHY		524309
+#define SRST_P_VCCIO6_IOC		524310
+#define SRST_OTGPHY_0			524311
+#define SRST_OTGPHY_1			524312
+#define SRST_HDPTX_INIT			524313
+#define SRST_HDPTX_CMN			524314
+#define SRST_HDPTX_LANE			524315
+#define SRST_HDMITXHPD			524317
+/********Name=PMU1SOFTRST_CON02,Offset=0x20A08********/
+#define SRST_MPHY_INIT			524320
+#define SRST_P_MPHY_GRF			524321
+#define SRST_P_VCCIO7_IOC		524323
+/********Name=PMU1SOFTRST_CON03,Offset=0x20A0C********/
+#define SRST_H_PMU1_BIU			524345
+#define SRST_P_PMU1_NIU			524346
+#define SRST_H_PMU_CM0_BIU		524347
+#define SRST_PMU_CM0_CORE		524348
+#define SRST_PMU_CM0_JTAG		524349
+/********Name=PMU1SOFTRST_CON04,Offset=0x20A10********/
+#define SRST_P_CRU_PMU1			524353
+#define SRST_P_PMU1_GRF			524355
+#define SRST_P_PMU1_IOC			524356
+#define SRST_P_PMU1WDT			524357
+#define SRST_T_PMU1WDT			524358
+#define SRST_P_PMUTIMER			524359
+#define SRST_PMUTIMER0			524361
+#define SRST_PMUTIMER1			524362
+#define SRST_P_PMU1PWM			524363
+#define SRST_PMU1PWM			524364
+/********Name=PMU1SOFTRST_CON05,Offset=0x20A14********/
+#define SRST_P_I2C0			524369
+#define SRST_I2C0			524371
+#define SRST_S_UART1			525373
+#define SRST_P_UART1			525374
+#define SRST_PDM0			524381
+#define SRST_H_PDM0			524383
+/********Name=PMU1SOFTRST_CON06,Offset=0xA18********/
+#define SRST_M_PDM0			524384
+#define SRST_H_VAD			524385
+/********Name=PMU1SOFTRST_CON07,Offset=0x20A1C********/
+#define SRST_P_PMU0GRF			524404
+#define SRST_P_PMU0IOC			524405
+#define SRST_P_GPIO0			524406
+#define SRST_DB_GPIO0			524407
+
+#define SRST_NR_RSTS			(SRST_DB_GPIO0 + 1)
+
+void pvtplls_cpub_suspend(void);
+void pvtplls_cpub_resume(void);
+
+void pvtplls_suspend(void);
+void pvtplls_resume(void);
+
+void rockchip_clock_init(void);
+
+#endif
diff --git a/plat/rockchip/rk3588/drivers/pmu/pmu.c b/plat/rockchip/rk3588/drivers/pmu/pmu.c
index a4128b2..16436dd 100644
--- a/plat/rockchip/rk3588/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3588/drivers/pmu/pmu.c
@@ -1319,12 +1319,16 @@
 					psci_power_state_t *target_state)
 {
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
 {
 	cpus_pd_req_enter_wfi();
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 void __dead2 rockchip_soc_soft_reset(void)
@@ -1352,6 +1356,8 @@
 	 * so we do not hope the core to execute valid codes.
 	 */
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 void __dead2 rockchip_soc_system_off(void)
@@ -1373,6 +1379,8 @@
 	 * so we do not hope the core to execute valid codes.
 	 */
 	psci_power_down_wfi();
+	/* should never reach here */
+	panic();
 }
 
 static void rockchip_pmu_pd_init(void)
diff --git a/plat/rpi/common/rpi3_pm.c b/plat/rpi/common/rpi3_pm.c
index 456e160..4dfe8f0 100644
--- a/plat/rpi/common/rpi3_pm.c
+++ b/plat/rpi/common/rpi3_pm.c
@@ -272,7 +272,7 @@
 	.pwr_domain_off = rpi3_pwr_domain_off,
 	.pwr_domain_on = rpi3_pwr_domain_on,
 	.pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
-	.pwr_domain_pwr_down_wfi = rpi3_pwr_down_wfi,
+	.pwr_domain_pwr_down = rpi3_pwr_down_wfi,
 	.system_off = rpi3_system_off,
 	.system_reset = rpi3_system_reset,
 	.validate_power_state = rpi3_validate_power_state,
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
index a371705..b009c5e 100644
--- a/plat/socionext/uniphier/uniphier_psci.c
+++ b/plat/socionext/uniphier/uniphier_psci.c
@@ -113,7 +113,7 @@
 	.pwr_domain_on = uniphier_psci_pwr_domain_on,
 	.pwr_domain_off = uniphier_psci_pwr_domain_off,
 	.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
-	.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = uniphier_psci_pwr_domain_pwr_down_wfi,
 	.system_off = uniphier_psci_system_off,
 	.system_reset = uniphier_psci_system_reset,
 };
diff --git a/plat/st/common/common_rules.mk b/plat/st/common/common_rules.mk
index 690507e..88c1087 100644
--- a/plat/st/common/common_rules.mk
+++ b/plat/st/common/common_rules.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+# Copyright (c) 2023-2025, STMicroelectronics - All Rights Reserved
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -41,7 +41,7 @@
 
 # Create DTB file for BL2
 ${BUILD_PLAT}/fdts/%-bl2.dts: fdts/%.dts fdts/${BL2_DTSI} | $$(@D)/
-	$(q)echo '#include "$(patsubst fdts/%,%,$<)"' > $@
+	$(q)echo '#include "$(patsubst %.dts,%$(SP_EXT).dts,$(patsubst fdts/%,%,$<))"' > $@
 	$(q)echo '#include "${BL2_DTSI}"' >> $@
 
 ${BUILD_PLAT}/fdts/%-bl2.dtb: ${BUILD_PLAT}/fdts/%-bl2.dts
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 3d37738..e700823 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -105,8 +105,13 @@
 ifeq ($(AARCH32_SP),sp_min)
 BL32_DTSI		:=	stm32mp15-bl32.dtsi
 FDT_SOURCES		+=	$(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dts,$(DTB_FILE_NAME)))
+ifneq (,$(wildcard $(patsubst %.dtb,fdts/%-sp_min.dts,$(DTB_FILE_NAME))))
+ifeq (,$(findstring -sp_min,$(DTB_FILE_NAME)))
+SP_EXT			:=	-sp_min
 endif
 endif
+endif
+endif
 
 # Macros and rules to build TF binary
 STM32_TF_STM32		:=	$(addprefix ${BUILD_PLAT}/tf-a-, $(patsubst %.dtb,%.stm32,$(DTB_FILE_NAME)))
@@ -258,7 +263,7 @@
 ifeq ($(AARCH32_SP),sp_min)
 # Create DTB file for BL32
 ${BUILD_PLAT}/fdts/%-bl32.dts: fdts/%.dts fdts/${BL32_DTSI} | $$(@D)/
-	$(q)echo '#include "$(patsubst fdts/%,%,$<)"' > $@
+	$(q)echo '#include "$(patsubst %.dts,%$(SP_EXT).dts,$(patsubst fdts/%,%,$<))"' > $@
 	$(q)echo '#include "${BL32_DTSI}"' >> $@
 
 ${BUILD_PLAT}/fdts/%-bl32.dtb: ${BUILD_PLAT}/fdts/%-bl32.dts | $$(@D)/
diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c
index 97e1ac6..7841022 100644
--- a/plat/st/stm32mp1/stm32mp1_pm.c
+++ b/plat/st/stm32mp1/stm32mp1_pm.c
@@ -215,7 +215,7 @@
 	.pwr_domain_suspend = stm32_pwr_domain_suspend,
 	.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = stm32_pwr_domain_pwr_down_wfi,
 	.system_off = stm32_system_off,
 	.system_reset = stm32_system_reset,
 	.validate_power_state = stm32_validate_power_state,
diff --git a/plat/st/stm32mp2/include/platform_def.h b/plat/st/stm32mp2/include/platform_def.h
index e720c02..523f9bb 100644
--- a/plat/st/stm32mp2/include/platform_def.h
+++ b/plat/st/stm32mp2/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2023-2025, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -73,8 +73,15 @@
 /*******************************************************************************
  * BL31 specific defines.
  ******************************************************************************/
+#if ENABLE_PIE
 #define BL31_BASE			0
-#define BL31_LIMIT			(STM32MP_SEC_SYSRAM_SIZE / 2)
+#else
+#define BL31_BASE			STM32MP_SYSRAM_BASE
+#endif
+
+#define BL31_LIMIT			(BL31_BASE + (STM32MP_SYSRAM_SIZE / 2))
+
+#define BL31_PROGBITS_LIMIT		(BL31_BASE + STM32MP_BL31_SIZE)
 
 /*******************************************************************************
  * BL33 specific defines.
diff --git a/plat/st/stm32mp2/platform.mk b/plat/st/stm32mp2/platform.mk
index a9f8d8f..d5e2785 100644
--- a/plat/st/stm32mp2/platform.mk
+++ b/plat/st/stm32mp2/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+# Copyright (c) 2023-2025, STMicroelectronics - All Rights Reserved
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -11,9 +11,12 @@
 include plat/st/common/common.mk
 
 CRASH_REPORTING			:=	1
-ENABLE_PIE			:=	1
+# Disable PIE by default. To re-enable it, uncomment next line.
+#ENABLE_PIE			:=	1
 PROGRAMMABLE_RESET_ADDRESS	:=	1
+ifeq ($(ENABLE_PIE),1)
 BL2_IN_XIP_MEM			:=	1
+endif
 
 STM32MP_BL33_EL1		?=	1
 ifeq ($(STM32MP_BL33_EL1),1)
diff --git a/plat/st/stm32mp2/stm32mp2_def.h b/plat/st/stm32mp2/stm32mp2_def.h
index b441502..3e60cad 100644
--- a/plat/st/stm32mp2/stm32mp2_def.h
+++ b/plat/st/stm32mp2/stm32mp2_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023-2024, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2023-2025, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -76,8 +76,6 @@
 #define RETRAM_BASE				U(0x0E080000)
 #define RETRAM_SIZE				U(0x00020000)
 
-#define STM32MP_SEC_SYSRAM_SIZE			STM32MP_SYSRAM_SIZE
-
 /* DDR configuration */
 #define STM32MP_DDR_BASE			U(0x80000000)
 #define STM32MP_DDR_MAX_SIZE			UL(0x100000000)	/* Max 4GB */
@@ -113,11 +111,9 @@
 #define STM32MP_BL2_SIZE			U(0x00029000) /* 164 KB for BL2 */
 
 /* Allocate remaining sysram to BL31 Binary only */
-#define STM32MP_BL31_SIZE			(STM32MP_SEC_SYSRAM_SIZE - \
+#define STM32MP_BL31_SIZE			(STM32MP_SYSRAM_SIZE - \
 						 STM32MP_BL2_SIZE)
 
-#define BL31_PROGBITS_LIMIT			STM32MP_BL31_SIZE
-
 #define STM32MP_BL2_BASE			(STM32MP_SYSRAM_BASE + \
 						 STM32MP_SYSRAM_SIZE - \
 						 STM32MP_BL2_SIZE)
diff --git a/plat/st/stm32mp2/stm32mp2_pm.c b/plat/st/stm32mp2/stm32mp2_pm.c
index 5bb381d..9be42c5 100644
--- a/plat/st/stm32mp2/stm32mp2_pm.c
+++ b/plat/st/stm32mp2/stm32mp2_pm.c
@@ -103,7 +103,7 @@
 	.pwr_domain_suspend = stm32_pwr_domain_suspend,
 	.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
-	.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
+	.pwr_domain_pwr_down = stm32_pwr_domain_pwr_down_wfi,
 	.system_off = stm32_system_off,
 	.system_reset = stm32_system_reset,
 	.validate_power_state = stm32_validate_power_state,
diff --git a/plat/xilinx/common/include/plat_fdt.h b/plat/xilinx/common/include/plat_fdt.h
index 47a678c..48ffff3 100644
--- a/plat/xilinx/common/include/plat_fdt.h
+++ b/plat/xilinx/common/include/plat_fdt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2023-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -8,9 +8,7 @@
 #define PLAT_FDT_H
 
 void prepare_dtb(void);
-
-#if defined(XILINX_OF_BOARD_DTB_ADDR)
+uintptr_t plat_retrieve_dt_addr(void);
 int32_t is_valid_dtb(void *fdt);
-#endif
 
 #endif /* PLAT_FDT_H */
diff --git a/plat/xilinx/common/include/pm_node.h b/plat/xilinx/common/include/pm_node.h
index 46f6bcf..3ee55c2 100644
--- a/plat/xilinx/common/include/pm_node.h
+++ b/plat/xilinx/common/include/pm_node.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -132,6 +132,18 @@
 	XPM_NODEIDX_DEV_TTC_2 = 0x26,
 	XPM_NODEIDX_DEV_TTC_3 = 0x27,
 	XPM_NODEIDX_DEV_SWDT_LPD = 0x28,
+	XPM_NODEIDX_DEV_I2C_2 = 0x117,
+	XPM_NODEIDX_DEV_I2C_3 = 0x118,
+	XPM_NODEIDX_DEV_I2C_4 = 0x119,
+	XPM_NODEIDX_DEV_I2C_5 = 0x11A,
+	XPM_NODEIDX_DEV_I2C_6 = 0x11B,
+	XPM_NODEIDX_DEV_I2C_7 = 0x11C,
+	XPM_NODEIDX_DEV_CAN_FD_2 = 0x11D,
+	XPM_NODEIDX_DEV_CAN_FD_3 = 0x11E,
+	XPM_NODEIDX_DEV_TTC_4 = 0x11F,
+	XPM_NODEIDX_DEV_TTC_5 = 0x120,
+	XPM_NODEIDX_DEV_TTC_6 = 0x121,
+	XPM_NODEIDX_DEV_TTC_7 = 0x122,
 
 	/* FPD Peripheral devices */
 	XPM_NODEIDX_DEV_SWDT_FPD = 0x29,
@@ -237,6 +249,11 @@
 	XPM_NODEIDX_DEV_FPD_SWDT_2 = 0xDD,
 	XPM_NODEIDX_DEV_FPD_SWDT_3 = 0xDE,
 #endif
+
+#if defined(PLAT_versal2)
+	XPM_NODEIDX_DEV_USB_1 = 0xD7,
+#endif
+
 	XPM_NODEIDX_DEV_MAX,
 };
 
diff --git a/plat/xilinx/common/plat_console.c b/plat/xilinx/common/plat_console.c
index 681226f..617a345 100644
--- a/plat/xilinx/common/plat_console.c
+++ b/plat/xilinx/common/plat_console.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2023-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -31,9 +31,7 @@
 static console_holder rt_hd_console;
 #endif
 
-#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
-	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
-				   !IS_TFA_IN_OCM(BL31_BASE)))
+#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && (XLNX_DT_CFG == 1))
 static dt_uart_info_t dt_uart_info;
 #endif
 
@@ -78,9 +76,7 @@
 	console_set_scope(console, consoleh->console_scope);
 }
 
-#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
-	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
-				   !IS_TFA_IN_OCM(BL31_BASE)))
+#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && (XLNX_DT_CFG == 1))
 /**
  * get_baudrate() - Get the baudrate form DTB.
  * @dtb: Address of the Device Tree Blob (DTB).
@@ -222,7 +218,7 @@
 static int fdt_get_uart_info(dt_uart_info_t *info)
 {
 	int node = 0, ret = 0;
-	void *dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+	void *dtb = (void *)plat_retrieve_dt_addr();
 
 	ret = is_valid_dtb(dtb);
 	if (ret < 0) {
@@ -259,9 +255,7 @@
 	/* For DT code decoding uncomment console registration below */
 	/* register_console(&boot_hd_console, &boot_console); */
 
-#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
-	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
-				   !IS_TFA_IN_OCM(BL31_BASE)))
+#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && (XLNX_DT_CFG == 1))
 	/* Parse DTB console for UART information  */
 	if (fdt_get_uart_info(&dt_uart_info) == 0) {
 		if (CONSOLE_IS(dtb)) {
@@ -280,16 +274,16 @@
 	INFO("BL31: Early console setup\n");
 
 #ifdef CONSOLE_RUNTIME
-#if (RT_CONSOLE_IS(dtb) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
-	       (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
-					!IS_TFA_IN_OCM(BL31_BASE)))
-	rt_hd_console.base = dt_uart_info.base;
-	rt_hd_console.baud_rate = dt_uart_info.baud_rate;
-	rt_hd_console.console_type = dt_uart_info.console_type;
-#else
 	rt_hd_console.base = (uintptr_t)RT_UART_BASE;
 	rt_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
 	rt_hd_console.console_type = RT_UART_TYPE;
+
+#if (RT_CONSOLE_IS(dtb) && (XLNX_DT_CFG == 1))
+	if (dt_uart_info.base != 0U) {
+		rt_hd_console.base = dt_uart_info.base;
+		rt_hd_console.baud_rate = dt_uart_info.baud_rate;
+		rt_hd_console.console_type = dt_uart_info.console_type;
+	}
 #endif
 
 	if ((rt_hd_console.console_type == boot_hd_console.console_type) &&
diff --git a/plat/xilinx/common/plat_fdt.c b/plat/xilinx/common/plat_fdt.c
index 4ad7b2d..62b46a9 100644
--- a/plat/xilinx/common/plat_fdt.c
+++ b/plat/xilinx/common/plat_fdt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2023-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -37,16 +37,15 @@
 {
 	int32_t ret = 0;
 
-	if (fdt_check_header(fdt) != 0) {
+	ret = fdt_check_header(fdt);
+	if (ret != 0) {
 		ERROR("Can't read DT at %p\n", fdt);
-		ret = -FDT_ERR_NOTFOUND;
 		goto error;
 	}
 
 	ret = fdt_open_into(fdt, fdt, XILINX_OF_BOARD_DTB_MAX_SIZE);
 	if (ret < 0) {
 		ERROR("Invalid Device Tree at %p: error %d\n", fdt, ret);
-		ret = -FDT_ERR_NOTFOUND;
 		goto error;
 	}
 
@@ -105,7 +104,7 @@
 	int map_ret = 0;
 	int ret = 0;
 
-	dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+	dtb = (void *)plat_retrieve_dt_addr();
 
 	if (!IS_TFA_IN_OCM(BL31_BASE)) {
 
@@ -156,4 +155,14 @@
 		}
 	}
 #endif
+}
+
+uintptr_t plat_retrieve_dt_addr(void)
+{
+	void *dtb = NULL;
+
+#if defined(XILINX_OF_BOARD_DTB_ADDR)
+	dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+#endif
+	return (uintptr_t)dtb;
 }
diff --git a/plat/xilinx/common/plat_xfer_list.c b/plat/xilinx/common/plat_xfer_list.c
deleted file mode 100644
index eae7ce4..0000000
--- a/plat/xilinx/common/plat_xfer_list.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#include <stddef.h>
-#include <arch_helpers.h>
-#include <common/debug.h>
-#include <lib/transfer_list.h>
-
-/*
- * FIXME: This address should come from firmware before TF-A runs
- * Having this to make sure the transfer list functionality works
- */
-#define FW_HANDOFF_BASE		U(0x1200000)
-#define FW_HANDOFF_SIZE		U(0x600000)
-
-static struct transfer_list_header *tl_hdr;
-
-int32_t transfer_list_populate_ep_info(entry_point_info_t *bl32,
-				       entry_point_info_t *bl33)
-{
-	struct transfer_list_entry *te = NULL;
-	struct entry_point_info *ep;
-	int32_t ret;
-
-	tl_hdr = (struct transfer_list_header *)FW_HANDOFF_BASE;
-	ret = transfer_list_check_header(tl_hdr);
-	if ((ret == TL_OPS_ALL) || (ret == TL_OPS_RO)) {
-		transfer_list_dump(tl_hdr);
-		while ((te = transfer_list_next(tl_hdr, te)) != NULL) {
-			ep = transfer_list_entry_data(te);
-			if (te->tag_id == TL_TAG_EXEC_EP_INFO64) {
-				switch (GET_SECURITY_STATE(ep->h.attr)) {
-				case NON_SECURE:
-					*bl33 = *ep;
-					continue;
-				case SECURE:
-					*bl32 = *ep;
-					continue;
-				default:
-					ERROR("Unrecognized Image Security State %lu\n",
-					      GET_SECURITY_STATE(ep->h.attr));
-					ret = TL_OPS_NON;
-				}
-			}
-		}
-	}
-	return ret;
-}
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
index 7c15be0..8be4be6 100644
--- a/plat/xilinx/versal/platform.mk
+++ b/plat/xilinx/versal/platform.mk
@@ -1,5 +1,5 @@
 # Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
-# Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
@@ -49,8 +49,12 @@
 endif
 
 ifdef XILINX_OF_BOARD_DTB_ADDR
+XLNX_DT_CFG     := 1
 $(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
+else
+XLNX_DT_CFG     := 0
 endif
+$(eval $(call add_define,XLNX_DT_CFG))
 
 PLAT_XLAT_TABLES_DYNAMIC := 0
 ifeq (${PLAT_XLAT_TABLES_DYNAMIC},1)
diff --git a/plat/xilinx/versal_net/platform.mk b/plat/xilinx/versal_net/platform.mk
index 9534118..25caab4 100644
--- a/plat/xilinx/versal_net/platform.mk
+++ b/plat/xilinx/versal_net/platform.mk
@@ -1,6 +1,6 @@
 # Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
 # Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
-# Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
@@ -68,8 +68,12 @@
 $(eval $(call add_define_val,VERSAL_NET_CONSOLE,VERSAL_NET_CONSOLE_ID_${VERSAL_NET_CONSOLE}))
 
 ifdef XILINX_OF_BOARD_DTB_ADDR
+XLNX_DT_CFG     := 1
 $(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
+else
+XLNX_DT_CFG     := 0
 endif
+$(eval $(call add_define,XLNX_DT_CFG))
 
 # Runtime console in default console in DEBUG build
 ifeq ($(DEBUG), 1)
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
index 0c83a56..9a9c8d1 100644
--- a/plat/xilinx/zynqmp/include/platform_def.h
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2014-2022, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -173,4 +173,10 @@
 	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI,	grp, \
 			GIC_INTR_CFG_EDGE)
 
+#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
+#define XLNX_DT_CFG 1
+#else
+#define XLNX_DT_CFG 0
+#endif
+
 #endif /* PLATFORM_DEF_H */
diff --git a/poetry.lock b/poetry.lock
index 4127bcd..d05e199 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
 
 [[package]]
 name = "alabaster"
@@ -281,6 +281,17 @@
 ]
 
 [[package]]
+name = "fdt"
+version = "0.3.3"
+description = "Flattened Device Tree Python Module"
+optional = false
+python-versions = ">=3.5"
+files = [
+    {file = "fdt-0.3.3-py3-none-any.whl", hash = "sha256:6b2fae2e8dfa38e9b0f9666aa001dd25be74e893d293a8d60001438f732e9e47"},
+    {file = "fdt-0.3.3.tar.gz", hash = "sha256:81a215930fef2ab8894913c4f474105bb53e14f07129fe07cb6eff2d5fdf26d2"},
+]
+
+[[package]]
 name = "filelock"
 version = "3.16.0"
 description = "A platform independent file lock."
@@ -538,6 +549,25 @@
 ]
 
 [[package]]
+name = "memory"
+version = "0.1.0"
+description = "A tool for analysis of static memory consumption by TF-A images"
+optional = false
+python-versions = "^3.8.0"
+files = []
+develop = true
+
+[package.dependencies]
+anytree = "^2.8.0"
+click = "^8.1.3"
+prettytable = "^3.5.0"
+pyelftools = "^0.29.0"
+
+[package.source]
+type = "directory"
+url = "tools/memory"
+
+[[package]]
 name = "myst-parser"
 version = "0.18.1"
 description = "An extended commonmark compliant parser, with bridges to docutils & sphinx."
@@ -1147,7 +1177,7 @@
 
 [package.dependencies]
 click = "^8.1.7"
-jinja2 = "^3.1.4"
+jinja2 = "^3.1.5"
 pyyaml = "^6.0.1"
 rich = "^10.14.0"
 tox = "^4.18.0"
@@ -1312,4 +1342,4 @@
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "6a6d2fe9390a4d7d1ecf808d5f303f2dc1eeb44736827b706a858046f3eea1db"
+content-hash = "c78729d7072714d77b4a69d6aabccab35dcf0548f08aa440ff178bc7bf2824be"
diff --git a/pyproject.toml b/pyproject.toml
index 62878b4..88c4753 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,16 +5,11 @@
 authors = ["Arm Ltd."]
 license = "BSD-3-Clause"
 readme = "readme.rst"
-packages = [
-	{ include = "memory", from = "tools/memory"}
-]
-
-[tool.poetry.scripts]
-memory = "memory.memmap:main"
 
 [tool.poetry.dependencies]
 python = "^3.8"
 cot-dt2c = {path = "tools/cot_dt2c", develop = true}
+memory = {path = "tools/memory", develop = true}
 tlc = {path = "tools/tlc", develop = true}
 
 [tool.poetry.group.docs]
@@ -30,9 +25,4 @@
 
 [tool.poetry.group.ci.dependencies]
 click = "^8.1.3"
-
-[tool.poetry.group.memory.dependencies]
-pyelftools = "^0.29"
-anytree = "^2.8.0"
-click = "^8.1.3"
-prettytable = "^3.5.0"
+fdt = "^0.3.0"
diff --git a/services/std_svc/drtm/drtm_main.c b/services/std_svc/drtm/drtm_main.c
index f58f615..117934f 100644
--- a/services/std_svc/drtm/drtm_main.c
+++ b/services/std_svc/drtm/drtm_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024 Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier:    BSD-3-Clause
  *
@@ -104,16 +104,18 @@
 	dlme_data_hdr_init.dlme_addr_map_size = drtm_get_address_map_size();
 	dlme_data_hdr_init.dlme_tcb_hashes_table_size =
 				plat_drtm_get_tcb_hash_table_size();
+	dlme_data_hdr_init.dlme_acpi_tables_region_size =
+				plat_drtm_get_acpi_tables_region_size();
 	dlme_data_hdr_init.dlme_impdef_region_size =
 				plat_drtm_get_imp_def_dlme_region_size();
 
-	dlme_data_min_size += dlme_data_hdr_init.dlme_addr_map_size +
+	dlme_data_min_size += sizeof(struct_dlme_data_header) +
+			      dlme_data_hdr_init.dlme_addr_map_size +
 			      ARM_DRTM_MIN_EVENT_LOG_SIZE +
 			      dlme_data_hdr_init.dlme_tcb_hashes_table_size +
+			      dlme_data_hdr_init.dlme_acpi_tables_region_size +
 			      dlme_data_hdr_init.dlme_impdef_region_size;
 
-	dlme_data_min_size = page_align(dlme_data_min_size, UP)/PAGE_SIZE;
-
 	/* Fill out platform DRTM features structure */
 	/* Only support default PCR schema (0x1) in this implementation. */
 	ARM_DRTM_TPM_FEATURES_SET_PCR_SCHEMA(plat_drtm_features.tpm_features,
@@ -123,7 +125,7 @@
 	ARM_DRTM_TPM_FEATURES_SET_FW_HASH(plat_drtm_features.tpm_features,
 		plat_tpm_feat->firmware_hash_algorithm);
 	ARM_DRTM_MIN_MEM_REQ_SET_MIN_DLME_DATA_SIZE(plat_drtm_features.minimum_memory_requirement,
-		dlme_data_min_size);
+		page_align(dlme_data_min_size, UP)/PAGE_SIZE);
 	ARM_DRTM_MIN_MEM_REQ_SET_DCE_SIZE(plat_drtm_features.minimum_memory_requirement,
 		plat_drtm_get_min_size_normal_world_dce());
 	ARM_DRTM_DMA_PROT_FEATURES_SET_MAX_REGIONS(plat_drtm_features.dma_prot_features,
@@ -132,6 +134,8 @@
 		plat_dma_prot_feat->dma_protection_support);
 	ARM_DRTM_TCB_HASH_FEATURES_SET_MAX_NUM_HASHES(plat_drtm_features.tcb_hash_features,
 		plat_drtm_get_tcb_hash_features());
+	ARM_DRTM_DLME_IMG_AUTH_SUPPORT(plat_drtm_features.dlme_image_auth_features,
+		plat_drtm_get_dlme_img_auth_features());
 
 	return 0;
 }
@@ -173,6 +177,12 @@
 		 plat_drtm_features.tcb_hash_features);
 }
 
+static inline uint64_t drtm_features_dlme_img_auth_features(void *ctx)
+{
+	SMC_RET2(ctx, 1ULL, /* DLME Image auth is supported */
+		 plat_drtm_features.dlme_image_auth_features);
+}
+
 static enum drtm_retc drtm_dl_check_caller_el(void *ctx)
 {
 	uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
@@ -237,7 +247,7 @@
 	 */
 	if (dlme_data_max_size < dlme_data_min_size) {
 		ERROR("%s: assertion failed:"
-		      " dlme_data_max_size (%ld) < dlme_data_total_bytes_req (%ld)\n",
+		      " dlme_data_max_size (%ld) < dlme_data_min_size (%ld)\n",
 		      __func__, dlme_data_max_size, dlme_data_min_size);
 		panic();
 	}
@@ -787,6 +797,12 @@
 				return drtm_features_tcb_hashes(handle);
 				break;	/* not reached */
 
+			case ARM_DRTM_FEATURES_DLME_IMG_AUTH:
+				INFO("++ DRTM service handler: "
+				     "DLME Image authentication features\n");
+				return drtm_features_dlme_img_auth_features(handle);
+				break;	/* not reached */
+
 			default:
 				ERROR("Unknown ARM DRTM service feature\n");
 				SMC_RET1(handle, NOT_SUPPORTED);
diff --git a/services/std_svc/drtm/drtm_main.h b/services/std_svc/drtm/drtm_main.h
index c105b56..44d0d2d 100644
--- a/services/std_svc/drtm/drtm_main.h
+++ b/services/std_svc/drtm/drtm_main.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024 Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier:    BSD-3-Clause
  *
@@ -45,7 +45,7 @@
  * Range(Min/Max) of DRTM parameter structure versions supported
  */
 #define ARM_DRTM_PARAMS_MIN_VERSION	U(1)
-#define ARM_DRTM_PARAMS_MAX_VERSION	U(1)
+#define ARM_DRTM_PARAMS_MAX_VERSION	U(2)
 
 enum drtm_dlme_el {
 	DLME_AT_EL1 = MODE_EL1,
@@ -74,6 +74,7 @@
 	uint64_t dma_prot_features;
 	uint64_t boot_pe_id;
 	uint64_t tcb_hash_features;
+	uint64_t dlme_image_auth_features;
 } drtm_features_t;
 
 struct __packed drtm_dl_args_v1 {
diff --git a/services/std_svc/drtm/drtm_measurements.c b/services/std_svc/drtm/drtm_measurements.c
index 8d514b7..d4f2b57 100644
--- a/services/std_svc/drtm/drtm_measurements.c
+++ b/services/std_svc/drtm/drtm_measurements.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier:    BSD-3-Clause
  *
@@ -198,6 +198,10 @@
 					       PCR_18);
 	CHECK_RC(rc,
 		 drtm_event_log_measure_and_record(DRTM_EVENT_ARM_SEPARATOR));
+
+	/* Measure no Action event but not extend it in PCR */
+	CHECK_RC(rc,
+		 drtm_event_log_measure_and_record(DRTM_EVENT_ARM_NO_ACTION));
 	/*
 	 * If the DCE is unable to log a measurement because there is no available
 	 * space in the event log region, the DCE must extend a hash of the value
diff --git a/services/std_svc/drtm/drtm_measurements.h b/services/std_svc/drtm/drtm_measurements.h
index 6d7a84e..f5a8c7c 100644
--- a/services/std_svc/drtm/drtm_measurements.h
+++ b/services/std_svc/drtm/drtm_measurements.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier:    BSD-3-Clause
  *
@@ -25,6 +25,9 @@
 #define DRTM_EVENT_ARM_DCE_SECONDARY	DRTM_EVENT_TYPE(8)
 #define DRTM_EVENT_ARM_TZFW		DRTM_EVENT_TYPE(9)
 #define DRTM_EVENT_ARM_SEPARATOR	DRTM_EVENT_TYPE(10)
+#define DRTM_EVENT_ARM_DLME_PUBKEY	DRTM_EVENT_TYPE(11)
+#define DRTM_EVENT_ARM_DLME_SVN		DRTM_EVENT_TYPE(12)
+#define DRTM_EVENT_ARM_NO_ACTION	DRTM_EVENT_TYPE(13)
 
 #define CHECK_RC(rc, func_call) { \
 	if (rc != 0) { \
diff --git a/services/std_svc/drtm/drtm_res_address_map.c b/services/std_svc/drtm/drtm_res_address_map.c
index 8636706..52e6eab 100644
--- a/services/std_svc/drtm/drtm_res_address_map.c
+++ b/services/std_svc/drtm/drtm_res_address_map.c
@@ -1,10 +1,11 @@
 /*
- * Copyright (c) 2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier:    BSD-3-Clause
  */
 
 #include <stdint.h>
+#include <stdlib.h>
 
 #include <plat/common/platform.h>
 #include <services/drtm_svc.h>
@@ -23,6 +24,20 @@
 
 static uint64_t drtm_address_map_size;
 
+static int compare_regions(const void *a, const void *b)
+{
+	const drtm_mem_region_t *region_a = (const drtm_mem_region_t *)a;
+	const drtm_mem_region_t *region_b = (const drtm_mem_region_t *)b;
+
+	if (region_a->region_address < region_b->region_address) {
+		return -1;
+	} else if (region_a->region_address > region_b->region_address) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
 drtm_memory_region_descriptor_table_t *drtm_build_address_map(void)
 {
 	/* Set up pointer to DRTM memory map. */
@@ -75,6 +90,9 @@
 
 	map->num_regions = i;
 
+	qsort(map->region, map->num_regions, sizeof(drtm_mem_region_t),
+	     compare_regions);
+
 	/* Store total size of address map. */
 	drtm_address_map_size = sizeof(drtm_memory_region_descriptor_table_t);
 	drtm_address_map_size += (i * sizeof(drtm_mem_region_t));
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index 4d82991..94634f2 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -222,6 +222,7 @@
 	 * in this scenario where execution was trapped to EL3 due to FIQ.
 	 */
 	simd_ctx_save(NON_SECURE, false);
+	simd_ctx_restore(SECURE);
 #endif
 #endif
 
@@ -238,14 +239,8 @@
 	/* Mark current core as handling a secure interrupt. */
 	ctx->secure_interrupt_ongoing = true;
 
-#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
-	simd_ctx_restore(SECURE);
-#endif
 	rc = spmd_spm_core_sync_entry(ctx);
 
-#if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
-	simd_ctx_save(SECURE, false);
-#endif
 	if (rc != 0ULL) {
 		ERROR("%s failed (%" PRId64 ") on CPU%u\n", __func__, rc, plat_my_core_pos());
 	}
@@ -258,6 +253,7 @@
 	cm_el1_sysregs_context_restore(NON_SECURE);
 
 #if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
+	simd_ctx_save(SECURE, false);
 	simd_ctx_restore(NON_SECURE);
 #endif
 #endif
diff --git a/tools/memory/__init__.py b/tools/memory/__init__.py
deleted file mode 100644
index 0b4c8d3..0000000
--- a/tools/memory/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python3
-
-#
-# Copyright (c) 2023, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
diff --git a/tools/memory/memory/__init__.py b/tools/memory/memory/__init__.py
deleted file mode 100644
index 0b4c8d3..0000000
--- a/tools/memory/memory/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python3
-
-#
-# Copyright (c) 2023, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
diff --git a/tools/memory/poetry.lock b/tools/memory/poetry.lock
new file mode 100644
index 0000000..2747479
--- /dev/null
+++ b/tools/memory/poetry.lock
@@ -0,0 +1,95 @@
+# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
+
+[[package]]
+name = "anytree"
+version = "2.12.1"
+description = "Powerful and Lightweight Python Tree Data Structure with various plugins"
+optional = false
+python-versions = ">=3.7.2,<4"
+files = [
+    {file = "anytree-2.12.1-py3-none-any.whl", hash = "sha256:5ea9e61caf96db1e5b3d0a914378d2cd83c269dfce1fb8242ce96589fa3382f0"},
+    {file = "anytree-2.12.1.tar.gz", hash = "sha256:244def434ccf31b668ed282954e5d315b4e066c4940b94aff4a7962d85947830"},
+]
+
+[package.dependencies]
+six = "*"
+
+[[package]]
+name = "click"
+version = "8.1.8"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
+    {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "prettytable"
+version = "3.11.0"
+description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "prettytable-3.11.0-py3-none-any.whl", hash = "sha256:aa17083feb6c71da11a68b2c213b04675c4af4ce9c541762632ca3f2cb3546dd"},
+    {file = "prettytable-3.11.0.tar.gz", hash = "sha256:7e23ca1e68bbfd06ba8de98bf553bf3493264c96d5e8a615c0471025deeba722"},
+]
+
+[package.dependencies]
+wcwidth = "*"
+
+[package.extras]
+tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"]
+
+[[package]]
+name = "pyelftools"
+version = "0.29"
+description = "Library for analyzing ELF files and DWARF debugging information"
+optional = false
+python-versions = "*"
+files = [
+    {file = "pyelftools-0.29-py2.py3-none-any.whl", hash = "sha256:519f38cf412f073b2d7393aa4682b0190fa901f7c3fa0bff2b82d537690c7fc1"},
+    {file = "pyelftools-0.29.tar.gz", hash = "sha256:ec761596aafa16e282a31de188737e5485552469ac63b60cfcccf22263fd24ff"},
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+    {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
+    {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.2.13"
+description = "Measures the displayed width of unicode strings in a terminal"
+optional = false
+python-versions = "*"
+files = [
+    {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
+    {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
+]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.8.0"
+content-hash = "d7c185b3dbfc9bba145f12146e18ce501caf081d7762f138bc5a7fde99f40543"
diff --git a/tools/memory/pyproject.toml b/tools/memory/pyproject.toml
new file mode 100644
index 0000000..c2fdfcb
--- /dev/null
+++ b/tools/memory/pyproject.toml
@@ -0,0 +1,21 @@
+[tool.poetry]
+name = "memory"
+version = "0.1.0"
+description = "A tool for analysis of static memory consumption by TF-A images"
+authors = ["Chris Kay <chris.kay@arm.com>", "Harrison Mutai <harrison.mutai@arm.com>"]
+license = "BSD-3-Clause"
+packages = [{include = "memory", from = "src"}]
+
+[tool.poetry.dependencies]
+anytree = "^2.8.0"
+click = "^8.1.3"
+prettytable = "^3.5.0"
+pyelftools = "^0.29.0"
+python = "^3.8.0"
+
+[tool.poetry.scripts]
+memory = "memory.memmap:main"
+
+[build-system]
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
diff --git a/tools/memory/src/memory/__init__.py b/tools/memory/src/memory/__init__.py
new file mode 100644
index 0000000..8e0db6b
--- /dev/null
+++ b/tools/memory/src/memory/__init__.py
@@ -0,0 +1,5 @@
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
diff --git a/tools/memory/memory/buildparser.py b/tools/memory/src/memory/buildparser.py
similarity index 97%
rename from tools/memory/memory/buildparser.py
rename to tools/memory/src/memory/buildparser.py
index dedff79..ea417e1 100755
--- a/tools/memory/memory/buildparser.py
+++ b/tools/memory/src/memory/buildparser.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023, Arm Limited. All rights reserved.
+# Copyright (c) 2023-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
diff --git a/tools/memory/memory/elfparser.py b/tools/memory/src/memory/elfparser.py
similarity index 98%
rename from tools/memory/memory/elfparser.py
rename to tools/memory/src/memory/elfparser.py
index 2dd2513..e6581c9 100644
--- a/tools/memory/memory/elfparser.py
+++ b/tools/memory/src/memory/elfparser.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023, Arm Limited. All rights reserved.
+# Copyright (c) 2023-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
diff --git a/tools/memory/memory/mapparser.py b/tools/memory/src/memory/mapparser.py
similarity index 97%
rename from tools/memory/memory/mapparser.py
rename to tools/memory/src/memory/mapparser.py
index ce4cc31..1c28e71 100644
--- a/tools/memory/memory/mapparser.py
+++ b/tools/memory/src/memory/mapparser.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2023-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
diff --git a/tools/memory/memory/memmap.py b/tools/memory/src/memory/memmap.py
similarity index 97%
rename from tools/memory/memory/memmap.py
rename to tools/memory/src/memory/memmap.py
index 34f5069..f46db8c 100755
--- a/tools/memory/memory/memmap.py
+++ b/tools/memory/src/memory/memmap.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 #
-# Copyright (c) 2023-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2023-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
diff --git a/tools/memory/memory/printer.py b/tools/memory/src/memory/printer.py
similarity index 98%
rename from tools/memory/memory/printer.py
rename to tools/memory/src/memory/printer.py
index 4b18560..f797139 100755
--- a/tools/memory/memory/printer.py
+++ b/tools/memory/src/memory/printer.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023, Arm Limited. All rights reserved.
+# Copyright (c) 2023-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
diff --git a/tools/sptool/hob.py b/tools/sptool/hob.py
new file mode 100644
index 0000000..dced086
--- /dev/null
+++ b/tools/sptool/hob.py
@@ -0,0 +1,425 @@
+#!/usr/bin/python3
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+import struct
+
+EFI_HOB_HANDOFF_TABLE_VERSION = 0x000A
+
+PAGE_SIZE_SHIFT = 12  # TODO assuming 4K page size
+
+# HobType values of EFI_HOB_GENERIC_HEADER.
+
+EFI_HOB_TYPE_HANDOFF = 0x0001
+EFI_HOB_TYPE_MEMORY_ALLOCATION = 0x0002
+EFI_HOB_TYPE_RESOURCE_DESCRIPTOR = 0x0003
+EFI_HOB_TYPE_GUID_EXTENSION = 0x0004
+EFI_HOB_TYPE_FV = 0x0005
+EFI_HOB_TYPE_CPU = 0x0006
+EFI_HOB_TYPE_MEMORY_POOL = 0x0007
+EFI_HOB_TYPE_FV2 = 0x0009
+EFI_HOB_TYPE_LOAD_PEIM_UNUSED = 0x000A
+EFI_HOB_TYPE_UEFI_CAPSULE = 0x000B
+EFI_HOB_TYPE_FV3 = 0x000C
+EFI_HOB_TYPE_UNUSED = 0xFFFE
+EFI_HOB_TYPE_END_OF_HOB_LIST = 0xFFFF
+
+# GUID values
+"""struct efi_guid {
+         uint32_t time_low;
+         uint16_t time_mid;
+         uint16_t time_hi_and_version;
+         uint8_t clock_seq_and_node[8];
+}"""
+
+MM_PEI_MMRAM_MEMORY_RESERVE_GUID = (
+    0x0703F912,
+    0xBF8D,
+    0x4E2A,
+    (0xBE, 0x07, 0xAB, 0x27, 0x25, 0x25, 0xC5, 0x92),
+)
+MM_NS_BUFFER_GUID = (
+    0xF00497E3,
+    0xBFA2,
+    0x41A1,
+    (0x9D, 0x29, 0x54, 0xC2, 0xE9, 0x37, 0x21, 0xC5),
+)
+
+# MMRAM states and capabilities
+# See UEFI Platform Initialization Specification Version 1.8, IV-5.3.5
+EFI_MMRAM_OPEN = 0x00000001
+EFI_MMRAM_CLOSED = 0x00000002
+EFI_MMRAM_LOCKED = 0x00000004
+EFI_CACHEABLE = 0x00000008
+EFI_ALLOCATED = 0x00000010
+EFI_NEEDS_TESTING = 0x00000020
+EFI_NEEDS_ECC_INITIALIZATION = 0x00000040
+
+EFI_SMRAM_OPEN = EFI_MMRAM_OPEN
+EFI_SMRAM_CLOSED = EFI_MMRAM_CLOSED
+EFI_SMRAM_LOCKED = EFI_MMRAM_LOCKED
+
+# EFI boot mode.
+EFI_BOOT_WITH_FULL_CONFIGURATION = 0x00
+EFI_BOOT_WITH_MINIMAL_CONFIGURATION = 0x01
+EFI_BOOT_ASSUMING_NO_CONFIGURATION_CHANGES = 0x02
+EFI_BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS = 0x03
+EFI_BOOT_WITH_DEFAULT_SETTINGS = 0x04
+EFI_BOOT_ON_S4_RESUME = 0x05
+EFI_BOOT_ON_S5_RESUME = 0x06
+EFI_BOOT_WITH_MFG_MODE_SETTINGS = 0x07
+EFI_BOOT_ON_S2_RESUME = 0x10
+EFI_BOOT_ON_S3_RESUME = 0x11
+EFI_BOOT_ON_FLASH_UPDATE = 0x12
+EFI_BOOT_IN_RECOVERY_MODE = 0x20
+
+STMM_BOOT_MODE = EFI_BOOT_WITH_FULL_CONFIGURATION
+STMM_MMRAM_REGION_STATE_DEFAULT = EFI_CACHEABLE | EFI_ALLOCATED
+STMM_MMRAM_REGION_STATE_HEAP = EFI_CACHEABLE
+
+"""`struct` python module allows user to specify endianness.
+We are expecting FVP or STMM platform as target and that they will be
+little-endian. See `struct` python module documentation if other endianness is
+needed."""
+ENDIANNESS = "<"
+
+
+def struct_pack_with_endianness(format_str, *args):
+    return struct.pack((ENDIANNESS + format_str), *args)
+
+
+def struct_calcsize_with_endianness(format_str):
+    return struct.calcsize(ENDIANNESS + format_str)
+
+
+# Helper for fdt node property parsing
+def get_integer_property_value(fdt_node, name):
+    if fdt_node.exist_property(name):
+        p = fdt_node.get_property(name)
+
+        # <u32> Device Tree value
+        if len(p) == 1:
+            return p.value
+        # <u64> Device Tree value represented as two 32-bit values
+        if len(p) == 2:
+            msb = p[0]
+            lsb = p[1]
+            return lsb | (msb << 32)
+    return None
+
+
+class EfiGuid:
+    """Class representing EFI GUID (Globally Unique Identifier) as described by
+    the UEFI Specification v2.10"""
+
+    def __init__(self, time_low, time_mid, time_hi_and_version, clock_seq_and_node):
+        self.time_low = time_low
+        self.time_mid = time_mid
+        self.time_hi_and_version = time_hi_and_version
+        self.clock_seq_and_node = clock_seq_and_node
+        self.format_str = "IHH8B"
+
+    def pack(self):
+        return struct_pack_with_endianness(
+            self.format_str,
+            self.time_low,
+            self.time_mid,
+            self.time_hi_and_version,
+            *self.clock_seq_and_node,
+        )
+
+    def __str__(self):
+        return f"{hex(self.time_low)}, {hex(self.time_mid)}, \
+    {hex(self.time_hi_and_version)}, {[hex(i) for i in self.clock_seq_and_node]}"
+
+
+class HobGenericHeader:
+    """Class representing the Hob Generic Header data type as described
+    in the UEFI Platform Initialization Specification version 1.8.
+
+    Each HOB is required to contain this header specifying the type and length
+    of the HOB.
+    """
+
+    def __init__(self, hob_type, hob_length):
+        self.format_str = "HHI"
+        self.hob_type = hob_type
+        self.hob_length = struct_calcsize_with_endianness(self.format_str) + hob_length
+        self.reserved = 0
+
+    def pack(self):
+        return struct_pack_with_endianness(
+            self.format_str, self.hob_type, self.hob_length, self.reserved
+        )
+
+    def __str__(self):
+        return f"Hob Type: {self.hob_type} Hob Length: {self.hob_length}"
+
+
+class HobGuid:
+    """Class representing the Guid Extension HOB as described in the UEFI
+    Platform Initialization Specification version 1.8.
+
+    Allows the production of HOBs whose types are not defined by the
+    specification by generating a GUID for the HOB entry."""
+
+    def __init__(self, name: EfiGuid, data_format_str, data):
+        hob_length = struct_calcsize_with_endianness(
+            name.format_str
+        ) + struct_calcsize_with_endianness(data_format_str)
+        self.header = HobGenericHeader(EFI_HOB_TYPE_GUID_EXTENSION, hob_length)
+        self.name = name
+        self.data = data
+        self.data_format_str = data_format_str
+        self.format_str = (
+            self.header.format_str + self.name.format_str + data_format_str
+        )
+
+    def pack(self):
+        return (
+            self.header.pack()
+            + self.name.pack()
+            + struct_pack_with_endianness(self.data_format_str, *self.data)
+        )
+
+    def __str__(self):
+        return f"Header: {self.header}\n Name: {self.name}\n Data: {self.data}"
+
+
+class HandoffInfoTable:
+    """Class representing the Handoff Info Table HOB (also known as PHIT HOB)
+    as described in the UEFI Platform Initialization Specification version 1.8.
+
+    Must be the first HOB in the HOB list. Contains general state
+    information.
+
+    For an SP, the range `memory_bottom` to `memory_top` will be the memory
+    range for the SP starting at the load address. `free_memory_bottom` to
+    `free_memory_top` indicates space where more HOB's could be added to the
+    HOB List."""
+
+    def __init__(self, memory_base, memory_size, free_memory_base, free_memory_size):
+        # header,uint32t,uint32t, uint64_t * 5
+        self.format_str = "II5Q"
+        hob_length = struct_calcsize_with_endianness(self.format_str)
+        self.header = HobGenericHeader(EFI_HOB_TYPE_HANDOFF, hob_length)
+        self.version = EFI_HOB_HANDOFF_TABLE_VERSION
+        self.boot_mode = STMM_BOOT_MODE
+        self.memory_top = memory_base + memory_size
+        self.memory_bottom = memory_base
+        self.free_memory_top = free_memory_base + free_memory_size
+        self.free_memory_bottom = free_memory_base + self.header.hob_length
+        self.hob_end = None
+
+    def set_hob_end_addr(self, hob_end_addr):
+        self.hob_end = hob_end_addr
+
+    def set_free_memory_bottom_addr(self, addr):
+        self.free_memory_bottom = addr
+
+    def pack(self):
+        return self.header.pack() + struct_pack_with_endianness(
+            self.format_str,
+            self.version,
+            self.boot_mode,
+            self.memory_top,
+            self.memory_bottom,
+            self.free_memory_top,
+            self.free_memory_bottom,
+            self.hob_end,
+        )
+
+
+class FirmwareVolumeHob:
+    """Class representing the Firmware Volume HOB type as described in the
+    UEFI Platform Initialization Specification version 1.8.
+
+    For an SP this will detail where the SP binary is located.
+    """
+
+    def __init__(self, base_address, img_offset, img_size):
+        # header, uint64_t, uint64_t
+        self.data_format_str = "2Q"
+        hob_length = struct_calcsize_with_endianness(self.data_format_str)
+        self.header = HobGenericHeader(EFI_HOB_TYPE_FV, hob_length)
+        self.format_str = self.header.format_str + self.data_format_str
+        self.base_address = base_address + img_offset
+        self.length = img_size - img_offset
+
+    def pack(self):
+        return self.header.pack() + struct_pack_with_endianness(
+            self.data_format_str, self.base_address, self.length
+        )
+
+
+class EndOfHobListHob:
+    """Class representing the End of HOB List HOB type as described in the
+    UEFI Platform Initialization Specification version 1.8.
+
+    Must be the last entry in a HOB list.
+    """
+
+    def __init__(self):
+        self.header = HobGenericHeader(EFI_HOB_TYPE_END_OF_HOB_LIST, 0)
+        self.format_str = ""
+
+    def pack(self):
+        return self.header.pack()
+
+
+class HobList:
+    """Class representing a HOB (Handoff Block list) based on the UEFI Platform
+    Initialization Sepcification version 1.8"""
+
+    def __init__(self, phit: HandoffInfoTable):
+        if phit is None:
+            raise Exception("HobList must be initialized with valid PHIT HOB")
+        final_hob = EndOfHobListHob()
+        phit.hob_end = phit.free_memory_bottom
+        phit.free_memory_bottom += final_hob.header.hob_length
+        self.hob_list = [phit, final_hob]
+
+    def add(self, hob):
+        if hob is not None:
+            if hob.header.hob_length > (
+                self.get_phit().free_memory_top - self.get_phit().free_memory_bottom
+            ):
+                raise MemoryError(
+                    f"Cannot add HOB of length {hob.header.hob_length}. \
+                    Resulting table size would exceed max table size of \
+                    {self.max_size}. Current table size: {self.size}."
+                )
+            self.hob_list.insert(-1, hob)
+            self.get_phit().hob_end += hob.header.hob_length
+            self.get_phit().free_memory_bottom += hob.header.hob_length
+
+    def get_list(self):
+        return self.hob_list
+
+    def get_phit(self):
+        if self.hob_list is not None:
+            if type(self.hob_list[0]) is not HandoffInfoTable:
+                raise Exception("First hob in list must be of type PHIT")
+            return self.hob_list[0]
+
+
+def generate_mmram_desc(base_addr, page_count, granule, region_state):
+    physical_size = page_count << (PAGE_SIZE_SHIFT + (granule << 1))
+    physical_start = base_addr
+    cpu_start = base_addr
+
+    return ("4Q", (physical_start, cpu_start, physical_size, region_state))
+
+
+def generate_stmm_region_descriptor(base_addr, physical_size):
+    region_state = STMM_MMRAM_REGION_STATE_DEFAULT
+    physical_start = base_addr
+    cpu_start = base_addr
+    return ("4Q", (physical_start, cpu_start, physical_size, region_state))
+
+
+def generate_ns_buffer_guid(mmram_desc):
+    return HobGuid(EfiGuid(*MM_NS_BUFFER_GUID), *mmram_desc)
+
+
+def generate_pei_mmram_memory_reserve_guid(regions):
+    # uint32t n_reserved regions, 4 bytes for padding so that array is aligned,
+    # array of mmram descriptors
+    format_str = "I4x"
+    data = [len(regions)]
+    for desc_format_str, mmram_desc in regions:
+        format_str += desc_format_str
+        data.extend(mmram_desc)
+    guid_data = (format_str, data)
+    return HobGuid(EfiGuid(*MM_PEI_MMRAM_MEMORY_RESERVE_GUID), *guid_data)
+
+
+def generate_hob_from_fdt_node(sp_fdt, hob_offset, hob_size=None):
+    """Create a HOB list binary from an SP FDT."""
+    fv_hob = None
+    ns_buffer_hob = None
+    mmram_reserve_hob = None
+    shared_buf_hob = None
+
+    load_address = get_integer_property_value(sp_fdt, "load-address")
+    img_size = get_integer_property_value(sp_fdt, "image-size")
+    entrypoint_offset = get_integer_property_value(sp_fdt, "entrypoint-offset")
+
+    if entrypoint_offset is None:
+        entrypoint_offset = 0x0
+    if hob_offset is None:
+        hob_offset = 0x0
+    if img_size is None:
+        img_size = 0x0
+
+    regions = []
+
+    # StMM requires the first memory region described in the
+    # MM_PEI_MMRAM_MEMORY_RESERVE_GUID describe the full partition layout.
+    regions.append(generate_stmm_region_descriptor(load_address, img_size))
+
+    if sp_fdt.exist_node("memory-regions"):
+        if sp_fdt.exist_property("xlat-granule"):
+            granule = int(sp_fdt.get_property("xlat-granule").value)
+        else:
+            # Default granule to 4K
+            granule = 0
+        memory_regions = sp_fdt.get_node("memory-regions")
+        for node in memory_regions.nodes:
+            base_addr = get_integer_property_value(node, "base-address")
+            page_count = get_integer_property_value(node, "pages-count")
+
+            if base_addr is None:
+                offset = get_integer_property_value(
+                    node, "load-address-relative-offset"
+                )
+                if offset is None:
+                    # Cannot create memory descriptor without base address, so skip
+                    # node if base address cannot be defined
+                    continue
+                else:
+                    base_addr = load_address + offset
+
+            if node.name.strip() == "heap":
+                region_state = STMM_MMRAM_REGION_STATE_HEAP
+            else:
+                region_state = STMM_MMRAM_REGION_STATE_DEFAULT
+
+            mmram_desc = generate_mmram_desc(
+                base_addr, page_count, granule, region_state
+            )
+
+            if node.name.strip() == "ns_comm_buffer":
+                ns_buffer_hob = generate_ns_buffer_guid(mmram_desc)
+
+            regions.append(mmram_desc)
+
+        mmram_reserve_hob = generate_pei_mmram_memory_reserve_guid(regions)
+
+    fv_hob = FirmwareVolumeHob(load_address, entrypoint_offset, img_size)
+    hob_list_base = load_address + hob_offset
+
+    # TODO assuming default of 1 page allocated for HOB List
+    if hob_size is not None:
+        max_table_size = hob_size
+    else:
+        max_table_size = 1 << PAGE_SIZE_SHIFT
+    phit = HandoffInfoTable(
+        load_address, entrypoint_offset + img_size, hob_list_base, max_table_size
+    )
+
+    # Create a HobList containing only PHIT and EndofHobList HOBs.
+    hob_list = HobList(phit)
+
+    # Add HOBs to HOB list
+    if fv_hob is not None:
+        hob_list.add(fv_hob)
+    if ns_buffer_hob is not None:
+        hob_list.add(ns_buffer_hob)
+    if mmram_reserve_hob is not None:
+        hob_list.add(mmram_reserve_hob)
+    if shared_buf_hob is not None:
+        hob_list.add(shared_buf_hob)
+
+    return hob_list
diff --git a/tools/sptool/sp_mk_generator.py b/tools/sptool/sp_mk_generator.py
index f80050e..9a00c74 100644
--- a/tools/sptool/sp_mk_generator.py
+++ b/tools/sptool/sp_mk_generator.py
@@ -55,10 +55,15 @@
 import re
 import sys
 import uuid
+import fdt
 from spactions import SpSetupActions
+import hob
+import struct
+from hob import HobList
 
 MAX_SP = 8
 UUID_LEN = 4
+HOB_OFFSET_DEFAULT=0x2000
 
 # Some helper functions to access args propagated to the action functions in
 # SpSetupActions framework.
@@ -179,6 +184,28 @@
     write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
     return args
 
+@SpSetupActions.sp_action(exec_order=1)
+def generate_hob_list(sp_layout, sp, args: dict):
+    '''
+        Generates a HOB file for the partition, if it requested it in its FF-A
+        manifest.
+    '''
+    with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as f:
+        sp_fdt = fdt.parse_dts(f.read())
+
+    if sp_fdt.exist_property('hob_list', '/boot-info'):
+        sp_hob_name = os.path.basename(sp + ".hob.bin")
+        sp_hob_name = os.path.join(args["out_dir"], f"{sp_hob_name}")
+
+        # Add to the args so it can be consumed by the TL pkg function.
+        sp_layout[sp]["hob_path"] = sp_hob_name
+        hob_list = hob.generate_hob_from_fdt_node(sp_fdt, HOB_OFFSET_DEFAULT)
+        with open(sp_hob_name, "wb") as h:
+            for block in hob_list.get_list():
+                h.write(block.pack())
+
+    return args
+
 def generate_sp_pkg(sp_node, pkg, sp_img, sp_dtb):
     ''' Generates the rule in case SP is to be generated in an SP Pkg. '''
     pm_offset = get_pm_offset(sp_node)
@@ -200,11 +227,12 @@
     TE_SP_BINARY = 0x103
     # TE Type for the HOB List.
     TE_HOB_LIST = 0x3
-    tlc_add_hob = f"\t$(Q)poetry run tlc add --entry {TE_HOB_LIST} {hob_path} {pkg}" if hob_path is not None else ""
+    tlc_add_hob = f"\t$(Q)$(TLCTOOL) add --entry {TE_HOB_LIST} {hob_path} {pkg}" if hob_path is not None else ""
     return f'''
 {pkg}: {sp_dtb} {sp_img}
 \t$(Q)echo Generating {pkg}
 \t$(Q)$(TLCTOOL) create --size {get_size(sp_node)} --entry {TE_FFA_MANIFEST} {sp_dtb} {pkg} --align 12
+{tlc_add_hob}
 \t$(Q)$(TLCTOOL) add --entry {TE_SP_BINARY} {sp_img} {pkg}
 '''
 
@@ -228,7 +256,10 @@
     if package_type == "sp_pkg":
         partition_pkg_rule = generate_sp_pkg(sp_layout[sp], pkg, sp_img, sp_dtb)
     elif package_type == "tl_pkg":
-        partition_pkg_rule = generate_tl_pkg(sp_layout[sp], pkg, sp_img, sp_dtb)
+        # Conditionally provide the Hob.
+        hob_path = sp_layout[sp]["hob_path"] if "hob_path" in sp_layout[sp] else None
+        partition_pkg_rule = generate_tl_pkg(
+                sp_layout[sp], pkg, sp_img, sp_dtb, hob_path)
     else:
         raise ValueError(f"Specified invalid pkg type {package_type}")