Merge "fix(psa): increase psa-mbedtls heap size for rsa" into integration
diff --git a/Makefile b/Makefile
index 384c1e4..6e0e584 100644
--- a/Makefile
+++ b/Makefile
@@ -882,6 +882,10 @@
 	CRYPTO_SUPPORT := 0
 endif #($(MEASURED_BOOT)-$(TRUSTED_BOARD_BOOT))
 
+ifneq ($(filter 1 2 3,$(CRYPTO_SUPPORT)),)
+CRYPTO_LIB := $(BUILD_PLAT)/lib/libmbedtls.a
+endif
+
 # SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled.
 ifeq ($(SDEI_SUPPORT)-$(SDEI_IN_FCONF),0-1)
         $(error "SDEI_IN_FCONF is only supported when SDEI_SUPPORT is enabled")
@@ -951,8 +955,21 @@
 	ifeq (${ENABLE_FEAT_RNG_TRAP},1)
                 $(error "ENABLE_FEAT_RNG_TRAP cannot be used with ARCH=aarch32")
 	endif
+
+	ifneq (${ENABLE_FEAT_FPMR},0)
+                $(error "ENABLE_FEAT_FPMR cannot be used with ARCH=aarch32")
+	endif
 endif #(ARCH=aarch32)
 
+ifneq (${ENABLE_FEAT_FPMR},0)
+	ifeq (${ENABLE_FEAT_FGT},0)
+                $(error "ENABLE_FEAT_FPMR requires ENABLE_FEAT_FGT")
+	endif
+	ifeq (${ENABLE_FEAT_HCX},0)
+                $(error "ENABLE_FEAT_FPMR requires ENABLE_FEAT_HCX")
+	endif
+endif #(ENABLE_FEAT_FPMR)
+
 ifneq (${ENABLE_SME_FOR_NS},0)
 	ifeq (${ENABLE_SVE_FOR_NS},0)
                 $(error "ENABLE_SME_FOR_NS requires ENABLE_SVE_FOR_NS")
@@ -1264,6 +1281,7 @@
 	ENABLE_FEAT_ECV \
 	ENABLE_FEAT_FGT \
 	ENABLE_FEAT_FGT2 \
+	ENABLE_FEAT_FPMR \
 	ENABLE_FEAT_HCX \
 	ENABLE_FEAT_LS64_ACCDATA \
 	ENABLE_FEAT_MTE2 \
@@ -1425,6 +1443,7 @@
 	ENABLE_MPMM_FCONF \
 	ENABLE_FEAT_FGT \
 	ENABLE_FEAT_FGT2 \
+	ENABLE_FEAT_FPMR \
 	ENABLE_FEAT_ECV \
 	ENABLE_FEAT_AMUv1p1 \
 	ENABLE_FEAT_SEL2 \
@@ -1741,8 +1760,8 @@
 	$(q)set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL))
 endif #(UNIX_MK)
 
-$(BUILD_PLAT)/romlib/romlib.bin $(BUILD_PLAT)/lib/libwrappers.a $&: $(BUILD_PLAT)/lib/libmbedtls.a $(BUILD_PLAT)/lib/libfdt.a $(BUILD_PLAT)/lib/libc.a
-	$(q)${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES=$(call escape-shell,$(INCLUDES)) DEFINES=$(call escape-shell,$(DEFINES)) --no-print-directory -C ${ROMLIBPATH} all
+$(BUILD_PLAT)/romlib/romlib.bin $(BUILD_PLAT)/lib/libwrappers.a $&: $(BUILD_PLAT)/lib/libfdt.a $(BUILD_PLAT)/lib/libc.a $(CRYPTO_LIB)
+	$(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
 ifdef UNIX_MK
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 336ad2b..2f9dc65 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -150,6 +150,10 @@
 BL31_SOURCES		+=	lib/extensions/trf/aarch64/trf.c
 endif
 
+ifneq (${ENABLE_FEAT_FPMR},0)
+BL31_SOURCES		+=	lib/extensions/fpmr/fpmr.c
+endif
+
 ifeq (${WORKAROUND_CVE_2017_5715},1)
 BL31_SOURCES		+=	lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S	\
 				lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 8c03ab8..0f6be9f 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -280,6 +280,12 @@
 			     ID_AA64MMFR3_EL1_D128_MASK);
 }
 
+static unsigned int read_feat_fpmr_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64pfr2_el1(), ID_AA64PFR2_EL1_FPMR_SHIFT,
+			     ID_AA64PFR2_EL1_FPMR_MASK);
+}
+
 /***********************************************************************************
  * TF-A supports many Arm architectural features starting from arch version
  * (8.0 till 8.7+). These features are mostly enabled through build flags. This
@@ -405,6 +411,8 @@
 		      "SME", 1, 2);
 	check_feature(ENABLE_SME2_FOR_NS, read_feat_sme_id_field(),
 		      "SME2", 2, 2);
+	check_feature(ENABLE_FEAT_FPMR, read_feat_fpmr_id_field(),
+		      "FPMR", 1, 1);
 
 	/* v9.3 features */
 	check_feature(ENABLE_FEAT_D128, read_feat_d128_id_field(),
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index fda43dc..f1cb73b 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -843,6 +843,9 @@
 - ``ERRATA_X4_2897503``: This applies errata 2897503 workaround to Cortex-X4
   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in r0p2.
 
+- ``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_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.
 
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 7d067c6..14eac5f 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -351,6 +351,12 @@
    This flag can take the values 0 to 2, to align  with the ``ENABLE_FEAT``
    mechanism. Default value is ``0``.
 
+-  ``ENABLE_FEAT_FPMR``: Numerical value to enable support for Floating Point
+   Mode Register feature, allowing access to the FPMR register. FPMR register
+   controls the behaviors of FP8 instructions. It is an optional architectural
+   feature from v9.2 and upwards. This flag can take value of 0 to 2, to align
+   with the ``FEATURE_DETECTION`` mechanism. Default value is ``0``.
+
 -  ``ENABLE_FEAT_FGT``: Numeric value to enable support for FGT (Fine Grain Traps)
    feature allowing for access to the HDFGRTR_EL2 (Hypervisor Debug Fine-Grained
    Read Trap Register) during EL2 to EL3 context save/restore operations.
@@ -708,6 +714,10 @@
    invert this behavior. Lower addresses will be printed at the top and higher
    addresses at the bottom.
 
+-  ``INIT_UNUSED_NS_EL2``: This build flag guards code that disables EL2
+   safely in scenario where NS-EL2 is present but unused. This flag is set to 0
+   by default. Platforms without NS-EL2 in use must enable this flag.
+
 -  ``KEY_ALG``: This build flag enables the user to select the algorithm to be
    used for generating the PKCS keys and subsequent signing of the certificate.
    It accepts 5 values: ``rsa``, ``rsa_1_5``, ``ecdsa``, ``ecdsa-brainpool-regular``
diff --git a/docs/plat/qti.rst b/docs/plat/qti.rst
index 1d483e7..0f89500 100644
--- a/docs/plat/qti.rst
+++ b/docs/plat/qti.rst
@@ -2,7 +2,7 @@
 ===========================
 
 Trusted Firmware-A (TF-A) implements the EL3 firmware layer for QTI SC7180,
-SC7280.
+SC7280 and QCS615.
 
 Boot Trace
 -------------
@@ -30,7 +30,8 @@
 
     make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sc7180 COREBOOT=1
 
-update value of CROSS_COMPILE argument with your cross-compilation toolchain.
+Update value of CROSS_COMPILE argument with your cross-compilation toolchain.
+Update the value of PLAT to be either of sc7180, sc7280 or qcs615
 
 Additional QTISECLIB_PATH=<path to qtiseclib> can be added in build command.
 if QTISECLIB_PATH is not added in build command stub implementation of qtiseclib
@@ -41,3 +42,4 @@
 `link <https://github.com/coreboot/qc_blobs/blob/master/sc7180/qtiseclib/libqtisec.a?raw=true>`__
 QTISELIB for SC7280 is available at
 `link <https://github.com/coreboot/qc_blobs/blob/master/sc7280/qtiseclib/libqtisec.a?raw=true>`__
+QTISECLIB for QCS615 is not available yet and currently compile with stubs only.
diff --git a/fdts/tc3-4-base.dtsi b/fdts/tc3-4-base.dtsi
index 2de5fd3..5ccfebb 100644
--- a/fdts/tc3-4-base.dtsi
+++ b/fdts/tc3-4-base.dtsi
@@ -52,6 +52,31 @@
 		};
 	};
 
+	rse_mbox_db_rx: mhu@RSE_MHU_RX_ADDR {
+		compatible = MHU_RX_COMPAT;
+		reg = <0x0 ADDRESSIFY(RSE_MHU_RX_ADDR) 0x0 MHU_OFFSET>;
+		clocks = <&soc_refclk>;
+		clock-names = "apb_pclk";
+		#mbox-cells = <MHU_MBOX_CELLS>;
+		interrupts = <GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupt-names = MHU_RX_INT_NAME;
+#if TARGET_FLAVOUR_FPGA
+		status = "disabled";
+#endif
+	};
+
+	rse_mbox_db_tx: mhu@RSE_MHU_TX_ADDR {
+		compatible = MHU_TX_COMPAT;
+		reg = <0x0 ADDRESSIFY(RSE_MHU_TX_ADDR) 0x0 MHU_OFFSET>;
+		clocks = <&soc_refclk>;
+		clock-names = "apb_pclk";
+		#mbox-cells = <MHU_MBOX_CELLS>;
+		interrupt-names = MHU_TX_INT_NAME;
+#if TARGET_FLAVOUR_FPGA
+		status = "disabled";
+#endif
+	};
+
 	gic: interrupt-controller@GIC_CTRL_ADDR {
 		ppi-partitions {
 			ppi_partition_little: interrupt-partition-0 {
@@ -80,5 +105,19 @@
 			mboxes = <&mbox_db_tx 0 0 0 &mbox_db_rx 0 0 0 &mbox_db_rx 0 0 1>;
 			shmem = <&cpu_scp_scmi_a2p &cpu_scp_scmi_p2a>;
 		};
+
+		rse {
+			compatible = "arm,rse";
+			mbox-names = "tx", "rx";
+			mboxes = <&rse_mbox_db_tx 0 0 0>, <&rse_mbox_db_rx 0 0 0>;
+#if TARGET_FLAVOUR_FPGA
+			status = "disabled";
+#endif
+		};
+	};
+
+	dsu-pmu {
+		compatible = "arm,dsu-pmu";
+		cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>;
 	};
 };
diff --git a/fdts/tc3.dts b/fdts/tc3.dts
index ffe3b6d..3b02f91 100644
--- a/fdts/tc3.dts
+++ b/fdts/tc3.dts
@@ -13,6 +13,9 @@
 #define MHU_TX_ADDR			46040000 /* hex */
 #define MHU_RX_ADDR			46140000 /* hex */
 
+#define RSE_MHU_TX_ADDR			49010000 /* hex */
+#define RSE_MHU_RX_ADDR			49110000 /* hex */
+
 #define LIT_CPU_PMU_COMPATIBLE		"arm,cortex-a520-pmu"
 #define MID_CPU_PMU_COMPATIBLE		"arm,cortex-a725-pmu"
 #define BIG_CPU_PMU_COMPATIBLE		"arm,cortex-x925-pmu"
@@ -74,11 +77,6 @@
 		status = "okay";
 	};
 
-	dsu-pmu {
-		compatible = "arm,dsu-pmu";
-		cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>;
-	};
-
 	ni-pmu {
 		compatible = "arm,ni-tower";
 		reg = <0x0 0x4f000000 0x0 0x4000000>;
diff --git a/fdts/tc4.dts b/fdts/tc4.dts
index 135d30a..8b73b49 100644
--- a/fdts/tc4.dts
+++ b/fdts/tc4.dts
@@ -17,6 +17,9 @@
 #define MID_CPU_PMU_COMPATIBLE		"arm,armv8-pmuv3"
 #define BIG_CPU_PMU_COMPATIBLE		"arm,armv8-pmuv3"
 
+#define RSE_MHU_TX_ADDR			49020000 /* hex */
+#define RSE_MHU_RX_ADDR			49030000 /* hex */
+
 #define ETHERNET_ADDR			64000000
 #define ETHERNET_INT			799
 
@@ -64,4 +67,8 @@
 		interrupt-names = "IRQAW";
 		iommus = <&smmu_700 0x200>;
 	};
+
+	dsu-pmu {
+		interrupts = <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH 0>;
+	};
 };
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 737d07a..3a7e2eb 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -465,6 +465,11 @@
 #define ID_AA64PFR2_EL1_MTEFAR_SHIFT		U(8)
 #define ID_AA64PFR2_EL1_MTEFAR_MASK		ULL(0xf)
 
+#define ID_AA64PFR2_EL1_FPMR_SHIFT		U(32)
+#define ID_AA64PFR2_EL1_FPMR_MASK		ULL(0xf)
+
+#define FPMR_IMPLEMENTED			ULL(0x1)
+
 #define VDISR_EL2				S3_4_C12_C1_1
 #define VSESR_EL2				S3_4_C5_C2_3
 
@@ -605,6 +610,7 @@
 #define SCR_NSE_SHIFT		U(62)
 #define SCR_FGTEN2_BIT		(UL(1) << 59)
 #define SCR_NSE_BIT		(ULL(1) << SCR_NSE_SHIFT)
+#define SCR_EnFPM_BIT		(ULL(1) << 50)
 #define SCR_GPF_BIT		(UL(1) << 48)
 #define SCR_D128En_BIT		(UL(1) << 47)
 #define SCR_TWEDEL_SHIFT	U(30)
@@ -1522,6 +1528,11 @@
  ******************************************************************************/
 #define CLUSTERPWRDN_EL1	S3_0_c15_c3_6
 
+/*******************************************************************************
+ * FEAT_FPMR - Floating point Mode Register
+ ******************************************************************************/
+#define FPMR			S3_3_C4_C4_2
+
 /* CLUSTERPWRDN_EL1 register definitions */
 #define DSU_CLUSTER_PWR_OFF	0
 #define DSU_CLUSTER_PWR_ON	1
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 59188da..8bdc13c 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -142,6 +142,8 @@
  * +----------------------------+
  * |	FEAT_LS64_ACCDATA	|
  * +----------------------------+
+ * |	FEAT_FPMR		|
+ * +----------------------------+
  */
 
 __attribute__((always_inline))
@@ -284,6 +286,12 @@
 		     ID_AA64MMFR3_EL1_D128_MASK, D128_IMPLEMENTED,
 		     ENABLE_FEAT_D128)
 
+/* FEAT_FPMR */
+CREATE_FEATURE_FUNCS(feat_fpmr, id_aa64pfr2_el1, ID_AA64PFR2_EL1_FPMR_SHIFT,
+		     ID_AA64PFR2_EL1_FPMR_MASK, FPMR_IMPLEMENTED,
+		     ENABLE_FEAT_FPMR)
+
+
 __attribute__((always_inline))
 static inline bool is_feat_sxpie_supported(void)
 {
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 119c428..3f3f14d 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -718,6 +718,8 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
 
+DEFINE_RENAME_SYSREG_RW_FUNCS(fpmr, FPMR)
+
 #define IS_IN_EL(x) \
 	(GET_EL(read_CurrentEl()) == MODE_EL##x)
 
diff --git a/include/lib/el3_runtime/context_el1.h b/include/lib/el3_runtime/context_el1.h
index 7bc0235..7fe43c7 100644
--- a/include/lib/el3_runtime/context_el1.h
+++ b/include/lib/el3_runtime/context_el1.h
@@ -194,6 +194,9 @@
 #define write_el1_ctx_common(ctx, reg, val)	((((ctx)->common).reg)	\
 							= (uint64_t) (val))
 
+#define write_el1_ctx_common_sysreg128(ctx, reg, val)	((((ctx)->common).reg)	\
+							= (sysreg_t) (val))
+
 #if NS_TIMER_SWITCH
 #define read_el1_ctx_arch_timer(ctx, reg)		(((ctx)->arch_timer).reg)
 #define write_el1_ctx_arch_timer(ctx, reg, val)	((((ctx)->arch_timer).reg)	\
@@ -295,11 +298,11 @@
 
 #if ENABLE_FEAT_THE
 #define read_el1_ctx_the(ctx, reg)		(((ctx)->the).reg)
-#define write_el1_ctx_the(ctx, reg, val)	((((ctx)->the).reg)	\
-							= (uint64_t) (val))
+#define write_el1_ctx_the_sysreg128(ctx, reg, val)	((((ctx)->the).reg)	\
+							= (sysreg_t) (val))
 #else
 #define read_el1_ctx_the(ctx, reg)		ULL(0)
-#define write_el1_ctx_the(ctx, reg, val)
+#define write_el1_ctx_the_sysreg128(ctx, reg, val)
 #endif /* ENABLE_FEAT_THE */
 
 #if ENABLE_FEAT_SCTLR2
diff --git a/include/lib/el3_runtime/context_el2.h b/include/lib/el3_runtime/context_el2.h
index 7374e39..f35a091 100644
--- a/include/lib/el3_runtime/context_el2.h
+++ b/include/lib/el3_runtime/context_el2.h
@@ -225,7 +225,7 @@
 #define write_el2_ctx_common(ctx, reg, val)	((((ctx)->common).reg)	\
 							= (uint64_t) (val))
 
-#define write_el2_ctx_sysreg128(ctx, reg, val)	((((ctx)->common).reg)	\
+#define write_el2_ctx_common_sysreg128(ctx, reg, val)	((((ctx)->common).reg)	\
 							= (sysreg_t) (val))
 
 #if ENABLE_FEAT_MTE2
@@ -268,12 +268,12 @@
 #define read_el2_ctx_vhe(ctx, reg)		(((ctx)->vhe).reg)
 #define write_el2_ctx_vhe(ctx, reg, val)	((((ctx)->vhe).reg)	\
 							= (uint64_t) (val))
-
 #define write_el2_ctx_vhe_sysreg128(ctx, reg, val)	((((ctx)->vhe).reg)	\
-								= (sysreg_t) (val))
+							= (sysreg_t) (val))
 #else
 #define read_el2_ctx_vhe(ctx, reg)		ULL(0)
 #define write_el2_ctx_vhe(ctx, reg, val)
+#define write_el2_ctx_vhe_sysreg128(ctx, reg, val)
 #endif /* ENABLE_FEAT_VHE */
 
 #if ENABLE_FEAT_RAS
diff --git a/include/lib/extensions/fpmr.h b/include/lib/extensions/fpmr.h
new file mode 100644
index 0000000..bc3ee9e
--- /dev/null
+++ b/include/lib/extensions/fpmr.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FPMR_H
+#define FPMR_H
+
+#include <context.h>
+
+#if ENABLE_FEAT_FPMR
+void fpmr_enable_per_world(per_world_context_t *per_world_ctx);
+#else
+static inline void fpmr_enable_per_world(per_world_context_t *per_world_ctx)
+{
+}
+#endif /* ENABLE_FEAT_FPMR */
+
+#endif /* FPMR_H */
diff --git a/lib/cpus/aarch64/cortex_x4.S b/lib/cpus/aarch64/cortex_x4.S
index 320fd90..4ff0ea5 100644
--- a/lib/cpus/aarch64/cortex_x4.S
+++ b/lib/cpus/aarch64/cortex_x4.S
@@ -75,6 +75,12 @@
 
 check_erratum_ls cortex_x4, ERRATUM(2897503), CPU_REV(0, 1)
 
+workaround_reset_start cortex_x4, ERRATUM(2923985), ERRATA_X4_2923985
+	sysreg_bit_set CORTEX_X4_CPUACTLR4_EL1, (BIT(11) | BIT(10))
+workaround_reset_end cortex_x4, ERRATUM(2923985)
+
+check_erratum_ls cortex_x4, ERRATUM(2923985), 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)
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 4c20785..4a04a9d 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -843,6 +843,10 @@
 # to revisions r0p0 and r0p1 of the Cortex-X4 cpu. It is fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_X4_2897503
 
+# Flag to apply erratum 2923985 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_2923985
+
 # 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
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 4ae1306..ca5e047 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -28,6 +28,7 @@
 #include <lib/extensions/brbe.h>
 #include <lib/extensions/debug_v8p9.h>
 #include <lib/extensions/fgt2.h>
+#include <lib/extensions/fpmr.h>
 #include <lib/extensions/mpam.h>
 #include <lib/extensions/pmuv3.h>
 #include <lib/extensions/sme.h>
@@ -291,6 +292,13 @@
 		scr_el3 |= SCR_D128En_BIT;
 	}
 
+	if (is_feat_fpmr_supported()) {
+		/* Set the EnFPM bit in SCR_EL3 to enable access to FPMR
+		 * register.
+		 */
+		scr_el3 |= SCR_EnFPM_BIT;
+	}
+
 	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
 
 	/* Initialize EL2 context registers */
@@ -714,6 +722,10 @@
 	if (is_feat_mpam_supported()) {
 		mpam_enable_per_world(&per_world_context[CPU_CONTEXT_NS]);
 	}
+
+	if (is_feat_fpmr_supported()) {
+		fpmr_enable_per_world(&per_world_context[CPU_CONTEXT_NS]);
+	}
 }
 #endif /* IMAGE_BL31 */
 
@@ -1352,8 +1364,8 @@
 	write_el2_ctx_common(ctx, vpidr_el2, read_vpidr_el2());
 	write_el2_ctx_common(ctx, vtcr_el2, read_vtcr_el2());
 
-	write_el2_ctx_sysreg128(ctx, ttbr0_el2, read_ttbr0_el2());
-	write_el2_ctx_sysreg128(ctx, vttbr_el2, read_vttbr_el2());
+	write_el2_ctx_common_sysreg128(ctx, ttbr0_el2, read_ttbr0_el2());
+	write_el2_ctx_common_sysreg128(ctx, vttbr_el2, read_vttbr_el2());
 }
 
 static void el2_sysregs_context_restore_common(el2_sysregs_t *ctx)
@@ -1679,15 +1691,12 @@
 	write_el1_ctx_common(ctx, csselr_el1, read_csselr_el1());
 	write_el1_ctx_common(ctx, sp_el1, read_sp_el1());
 	write_el1_ctx_common(ctx, esr_el1, read_esr_el1());
-	write_el1_ctx_common(ctx, ttbr0_el1, read_ttbr0_el1());
-	write_el1_ctx_common(ctx, ttbr1_el1, read_ttbr1_el1());
 	write_el1_ctx_common(ctx, mair_el1, read_mair_el1());
 	write_el1_ctx_common(ctx, amair_el1, read_amair_el1());
 	write_el1_ctx_common(ctx, actlr_el1, read_actlr_el1());
 	write_el1_ctx_common(ctx, tpidr_el1, read_tpidr_el1());
 	write_el1_ctx_common(ctx, tpidr_el0, read_tpidr_el0());
 	write_el1_ctx_common(ctx, tpidrro_el0, read_tpidrro_el0());
-	write_el1_ctx_common(ctx, par_el1, read_par_el1());
 	write_el1_ctx_common(ctx, far_el1, read_far_el1());
 	write_el1_ctx_common(ctx, afsr0_el1, read_afsr0_el1());
 	write_el1_ctx_common(ctx, afsr1_el1, read_afsr1_el1());
@@ -1696,6 +1705,10 @@
 	write_el1_ctx_common(ctx, mdccint_el1, read_mdccint_el1());
 	write_el1_ctx_common(ctx, mdscr_el1, read_mdscr_el1());
 
+	write_el1_ctx_common_sysreg128(ctx, par_el1, read_par_el1());
+	write_el1_ctx_common_sysreg128(ctx, ttbr0_el1, read_ttbr0_el1());
+	write_el1_ctx_common_sysreg128(ctx, ttbr1_el1, read_ttbr1_el1());
+
 	if (CTX_INCLUDE_AARCH32_REGS) {
 		/* Save Aarch32 registers */
 		write_el1_ctx_aarch32(ctx, spsr_abt, read_spsr_abt());
@@ -1760,8 +1773,8 @@
 	}
 
 	if (is_feat_the_supported()) {
-		write_el1_ctx_the(ctx, rcwmask_el1, read_rcwmask_el1());
-		write_el1_ctx_the(ctx, rcwsmask_el1, read_rcwsmask_el1());
+		write_el1_ctx_the_sysreg128(ctx, rcwmask_el1, read_rcwmask_el1());
+		write_el1_ctx_the_sysreg128(ctx, rcwsmask_el1, read_rcwsmask_el1());
 	}
 
 	if (is_feat_sctlr2_supported()) {
diff --git a/lib/extensions/fpmr/fpmr.c b/lib/extensions/fpmr/fpmr.c
new file mode 100644
index 0000000..8e37e7a
--- /dev/null
+++ b/lib/extensions/fpmr/fpmr.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/extensions/fpmr.h>
+
+void fpmr_enable_per_world(per_world_context_t *per_world_ctx)
+{
+	u_register_t reg;
+
+	/* Disable Floating point Trap in CPTR_EL3. */
+	reg = per_world_ctx->ctx_cptr_el3;
+	reg &= ~TFP_BIT;
+	per_world_ctx->ctx_cptr_el3 = reg;
+}
diff --git a/lib/romlib/Makefile b/lib/romlib/Makefile
index bc31a2f..01a0395 100644
--- a/lib/romlib/Makefile
+++ b/lib/romlib/Makefile
@@ -12,17 +12,26 @@
 BUILD_DIR   = $(BUILD_PLAT)/romlib
 LIB_DIR     = $(BUILD_PLAT)/lib
 WRAPPER_DIR = $(BUILD_PLAT)/libwrapper
-LIBS        = $(LIB_DIR)/libmbedtls.a $(LIB_DIR)/libfdt.a $(LIB_DIR)/libc.a
+LIBS        = $(LIB_DIR)/libfdt.a $(LIB_DIR)/libc.a
 INC         = $(INCLUDES:-I%=-I../../%)
 PPFLAGS     = $(INC) $(DEFINES) -P -x assembler-with-cpp -D__LINKER__ -MD -MP -MT $(BUILD_DIR)/romlib.ld
 OBJS        = $(BUILD_DIR)/jmptbl.o $(BUILD_DIR)/init.o
 MAPFILE     = $(BUILD_PLAT)/romlib/romlib.map
 
-ifneq ($(PLAT_DIR),)
-        WRAPPER_SOURCES = $(sort $(shell $(ROMLIB_GEN) genwrappers -b $\
-                $(WRAPPER_DIR) --list ../../$(PLAT_DIR)/jmptbl.i))
+PROCESSED_JMPTBL = ../../$(PLAT_DIR)/jmptbl.i
+
+# 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)
+    LIBS += $(LIB_DIR)/libmbedtls.a
+endif
 
-        WRAPPER_OBJS = $(WRAPPER_SOURCES:.s=.o)
+ifneq ($(PLAT_DIR),)
+    # Generate wrapper sources and objects
+    WRAPPER_SOURCES = $(sort $(shell $(ROMLIB_GEN) genwrappers -b $\
+                $(WRAPPER_DIR) --list $(PROCESSED_JMPTBL)))
+    WRAPPER_OBJS = $(WRAPPER_SOURCES:.s=.o)
 endif
 
 LDFLAGS := -Wl,--gc-sections -nostdlib
@@ -69,21 +78,21 @@
 	$(s)echo "  AR      $@"
 	$(q)$(aarch64-ar) -rc $@ $(WRAPPER_DIR)/jmpvar.o $(WRAPPER_OBJS)
 
-$(BUILD_DIR)/jmptbl.i: ../../$(PLAT_DIR)/jmptbl.i | $$(@D)/
+$(BUILD_DIR)/jmptbl.i: $(PROCESSED_JMPTBL) | $$(@D)/
 	$(s)echo "  PRE     $@"
 	$(q)$(ROMLIB_GEN) pre --output $@ --deps $(BUILD_DIR)/jmptbl.d $<
 
-$(WRAPPER_SOURCES) $&: $(BUILD_DIR)/jmptbl.i | $$(@D)/
+$(WRAPPER_SOURCES) $&: $(PROCESSED_JMPTBL) | $$(@D)/
 	$(s)echo "  WRP     $<"
 	$(q)$(ROMLIB_GEN) genwrappers --bti=$(ENABLE_BTI) -b $(WRAPPER_DIR) $<
 
 $(WRAPPER_OBJS): $(WRAPPER_DIR)/%.o: $(WRAPPER_DIR)/%.s | $$(@D)/
 
-$(BUILD_DIR)/jmptbl.s: $(BUILD_DIR)/jmptbl.i | $$(@D)/
+$(BUILD_DIR)/jmptbl.s: $(PROCESSED_JMPTBL) | $$(@D)/
 	$(s)echo "  TBL     $@"
 	$(q)$(ROMLIB_GEN) gentbl --output $@ --bti=$(ENABLE_BTI) $<
 
-$(BUILD_DIR)/romlib.ldflags: ../../$(PLAT_DIR)/jmptbl.i | $$(@D)/
+$(BUILD_DIR)/romlib.ldflags: $(PROCESSED_JMPTBL) | $$(@D)/
 	$(s)echo "  LDFLAGS $@"
 	$(q)$(ROMLIB_GEN) link-flags $< > $@
 
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
index 57609d5..a1db0b8 100644
--- a/make_helpers/arch_features.mk
+++ b/make_helpers/arch_features.mk
@@ -408,6 +408,9 @@
 # if FEAT_BRBE is implemented.
 ENABLE_BRBE_FOR_NS			?=	0
 
+# Flag to enable Floating point exception Mode Register Feature (FEAT_FPMR)
+ENABLE_FEAT_FPMR			?=	0
+
 #----
 # 9.3
 #----
diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i
index 077283e..a23de73 100644
--- a/plat/arm/board/fvp/jmptbl.i
+++ b/plat/arm/board/fvp/jmptbl.i
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -37,28 +37,5 @@
 fdt     fdt_get_alias
 fdt     fdt_node_offset_by_phandle
 fdt     fdt_add_subnode
-mbedtls mbedtls_asn1_get_alg
-mbedtls mbedtls_asn1_get_alg_null
-mbedtls mbedtls_asn1_get_bitstring_null
-mbedtls mbedtls_asn1_get_bool
-mbedtls mbedtls_asn1_get_int
-mbedtls mbedtls_asn1_get_len
-mbedtls mbedtls_asn1_get_tag
-mbedtls mbedtls_free
-mbedtls mbedtls_md
-mbedtls mbedtls_md_get_size
-mbedtls mbedtls_memory_buffer_alloc_init
-mbedtls mbedtls_oid_get_md_alg
-mbedtls mbedtls_oid_get_numeric_string
-mbedtls mbedtls_oid_get_pk_alg
-mbedtls mbedtls_oid_get_sig_alg
-mbedtls mbedtls_pk_free
-mbedtls mbedtls_pk_init
-mbedtls mbedtls_pk_parse_subpubkey
-mbedtls mbedtls_pk_verify_ext
-mbedtls mbedtls_platform_set_snprintf
-mbedtls mbedtls_x509_get_rsassa_pss_params
-mbedtls mbedtls_x509_get_sig_alg
-mbedtls mbedtls_md_info_from_type
 c       exit
 c       atexit
diff --git a/plat/arm/board/fvp/jmptbl_mbedtls.i b/plat/arm/board/fvp/jmptbl_mbedtls.i
new file mode 100644
index 0000000..6e1f017
--- /dev/null
+++ b/plat/arm/board/fvp/jmptbl_mbedtls.i
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform-specific ROMLIB MbedTLS functions can be added here.
+# During the build process, this file is appended to jmptbl.i
+# if MbedTLS support is required.
+#
+# Format:
+# lib   function        [patch]
+# Example:
+# mbedtls mbedtls_asn1_get_alg
+# mbedtls mbedtls_asn1_get_alg_null patch
+
+mbedtls mbedtls_asn1_get_alg
+mbedtls mbedtls_asn1_get_alg_null
+mbedtls mbedtls_asn1_get_bitstring_null
+mbedtls mbedtls_asn1_get_bool
+mbedtls mbedtls_asn1_get_int
+mbedtls mbedtls_asn1_get_len
+mbedtls mbedtls_asn1_get_tag
+mbedtls mbedtls_free
+mbedtls mbedtls_md
+mbedtls mbedtls_md_get_size
+mbedtls mbedtls_memory_buffer_alloc_init
+mbedtls mbedtls_oid_get_md_alg
+mbedtls mbedtls_oid_get_numeric_string
+mbedtls mbedtls_oid_get_pk_alg
+mbedtls mbedtls_oid_get_sig_alg
+mbedtls mbedtls_pk_free
+mbedtls mbedtls_pk_init
+mbedtls mbedtls_pk_parse_subpubkey
+mbedtls mbedtls_pk_verify_ext
+mbedtls mbedtls_platform_set_snprintf
+mbedtls mbedtls_x509_get_rsassa_pss_params
+mbedtls mbedtls_x509_get_sig_alg
+mbedtls mbedtls_md_info_from_type
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 1340a65..3b638e4 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -57,6 +57,7 @@
       ENABLE_BRBE_FOR_NS	:= 2
       ENABLE_TRBE_FOR_NS	:= 2
       ENABLE_FEAT_D128		:= 2
+      ENABLE_FEAT_FPMR		:= 2
 endif
 
 ENABLE_SYS_REG_TRACE_FOR_NS	:= 2
diff --git a/plat/arm/board/juno/jmptbl.i b/plat/arm/board/juno/jmptbl.i
index 327a345..a62661d 100644
--- a/plat/arm/board/juno/jmptbl.i
+++ b/plat/arm/board/juno/jmptbl.i
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -36,28 +36,5 @@
 fdt     fdt_node_offset_by_phandle
 fdt     fdt_subnode_offset
 fdt     fdt_add_subnode
-mbedtls mbedtls_asn1_get_alg
-mbedtls mbedtls_asn1_get_alg_null
-mbedtls mbedtls_asn1_get_bitstring_null
-mbedtls mbedtls_asn1_get_bool
-mbedtls mbedtls_asn1_get_int
-mbedtls mbedtls_asn1_get_len
-mbedtls mbedtls_asn1_get_tag
-mbedtls mbedtls_free
-mbedtls mbedtls_md
-mbedtls mbedtls_md_get_size
-mbedtls mbedtls_memory_buffer_alloc_init
-mbedtls mbedtls_oid_get_md_alg
-mbedtls mbedtls_oid_get_numeric_string
-mbedtls mbedtls_oid_get_pk_alg
-mbedtls mbedtls_oid_get_sig_alg
-mbedtls mbedtls_pk_free
-mbedtls mbedtls_pk_init
-mbedtls mbedtls_pk_parse_subpubkey
-mbedtls mbedtls_pk_verify_ext
-mbedtls mbedtls_platform_set_snprintf
-mbedtls mbedtls_x509_get_rsassa_pss_params
-mbedtls mbedtls_x509_get_sig_alg
-mbedtls mbedtls_md_info_from_type
 c       exit
 c       atexit
diff --git a/plat/arm/board/juno/jmptbl_mbedtls.i b/plat/arm/board/juno/jmptbl_mbedtls.i
new file mode 100644
index 0000000..6e1f017
--- /dev/null
+++ b/plat/arm/board/juno/jmptbl_mbedtls.i
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform-specific ROMLIB MbedTLS functions can be added here.
+# During the build process, this file is appended to jmptbl.i
+# if MbedTLS support is required.
+#
+# Format:
+# lib   function        [patch]
+# Example:
+# mbedtls mbedtls_asn1_get_alg
+# mbedtls mbedtls_asn1_get_alg_null patch
+
+mbedtls mbedtls_asn1_get_alg
+mbedtls mbedtls_asn1_get_alg_null
+mbedtls mbedtls_asn1_get_bitstring_null
+mbedtls mbedtls_asn1_get_bool
+mbedtls mbedtls_asn1_get_int
+mbedtls mbedtls_asn1_get_len
+mbedtls mbedtls_asn1_get_tag
+mbedtls mbedtls_free
+mbedtls mbedtls_md
+mbedtls mbedtls_md_get_size
+mbedtls mbedtls_memory_buffer_alloc_init
+mbedtls mbedtls_oid_get_md_alg
+mbedtls mbedtls_oid_get_numeric_string
+mbedtls mbedtls_oid_get_pk_alg
+mbedtls mbedtls_oid_get_sig_alg
+mbedtls mbedtls_pk_free
+mbedtls mbedtls_pk_init
+mbedtls mbedtls_pk_parse_subpubkey
+mbedtls mbedtls_pk_verify_ext
+mbedtls mbedtls_platform_set_snprintf
+mbedtls mbedtls_x509_get_rsassa_pss_params
+mbedtls mbedtls_x509_get_sig_alg
+mbedtls mbedtls_md_info_from_type
diff --git a/plat/arm/board/tc/include/tc_helpers.S b/plat/arm/board/tc/include/tc_helpers.S
index 9adf09a..48ca16c 100644
--- a/plat/arm/board/tc/include/tc_helpers.S
+++ b/plat/arm/board/tc/include/tc_helpers.S
@@ -82,6 +82,9 @@
 endfunc TC_HANDLER(3)
 
 func TC_HANDLER(4)
+	mov	x9, lr
+	bl	enable_dsu_pmu_el1_access
+	mov	lr, x9
 	ret
 endfunc TC_HANDLER(4)
 
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 3178c06..759c85d 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -230,18 +230,17 @@
 # Add the HW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${TC_HW_CONFIG},--hw-config,${TC_HW_CONFIG}))
 
+$(info Including rse_comms.mk)
+include drivers/arm/rse/rse_comms.mk
+
+BL1_SOURCES	+=	${RSE_COMMS_SOURCES}
+BL2_SOURCES	+=	${RSE_COMMS_SOURCES}
+BL31_SOURCES	+=	${RSE_COMMS_SOURCES}
+
 # Include Measured Boot makefile before any Crypto library makefile.
 # Crypto library makefile may need default definitions of Measured Boot build
 # flags present in Measured Boot makefile.
-$(info Including rse_comms.mk)
 ifeq (${MEASURED_BOOT},1)
-        $(info Including rse_comms.mk)
-        include drivers/arm/rse/rse_comms.mk
-
-	BL1_SOURCES	+=	${RSE_COMMS_SOURCES}
-	BL2_SOURCES	+=	${RSE_COMMS_SOURCES}
-	PLAT_INCLUDES	+=	-Iinclude/lib/psa
-
     ifeq (${DICE_PROTECTION_ENVIRONMENT},1)
         $(info Including qcbor.mk)
         include drivers/measured_boot/rse/qcbor.mk
diff --git a/plat/arm/board/tc/tc_bl31_setup.c b/plat/arm/board/tc/tc_bl31_setup.c
index 801872a..3fb0214 100644
--- a/plat/arm/board/tc/tc_bl31_setup.c
+++ b/plat/arm/board/tc/tc_bl31_setup.c
@@ -25,6 +25,10 @@
 #include <psa/crypto_types.h>
 #include <psa/crypto_values.h>
 #endif /* PLATFORM_TEST_TFM_TESTSUITE */
+#include <psa/error.h>
+
+#include <drivers/arm/rse_comms.h>
+#include <plat/common/platform.h>
 
 #ifdef PLATFORM_TEST_TFM_TESTSUITE
 /*
@@ -190,6 +194,12 @@
 	plat_arm_secure_wdt_start();
 
 	arm_bl31_plat_runtime_setup();
+
+	/* Initialise RSE communication channel */
+	status = rse_comms_init(PLAT_RSE_AP_SND_MHU_BASE, PLAT_RSE_AP_RCV_MHU_BASE);
+	if (status != PSA_SUCCESS) {
+		ERROR("Failed to initialize RSE communication channel - psa_status = %d\n", status);
+	}
 }
 
 void bl31_plat_runtime_setup(void)
diff --git a/plat/arm/board/tc/tc_plat.c b/plat/arm/board/tc/tc_plat.c
index fed14f7..1ecfdb9 100644
--- a/plat/arm/board/tc/tc_plat.c
+++ b/plat/arm/board/tc/tc_plat.c
@@ -40,6 +40,7 @@
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
 	TC_FLASH0_RO,
+	ARM_V2M_MAP_MEM_PROTECT,
 	TC_MAP_DEVICE,
 	TC_MAP_NS_DRAM1,
 #if defined(SPD_spmd)
@@ -65,6 +66,7 @@
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_IOFPGA,
+	ARM_V2M_MAP_MEM_PROTECT,
 	TC_MAP_DEVICE,
 	PLAT_DTB_DRAM_NS,
 #if SPM_MM
diff --git a/plat/mediatek/mt8196/include/platform_def.h b/plat/mediatek/mt8196/include/platform_def.h
index 5b45d92..630a3f0 100644
--- a/plat/mediatek/mt8196/include/platform_def.h
+++ b/plat/mediatek/mt8196/include/platform_def.h
@@ -128,6 +128,14 @@
 #define VDOSYS1_BASE		(IO_PHYS + 0x0C100000)
 
 /*******************************************************************************
+ * DP related constants
+ ******************************************************************************/
+#define EDP_SEC_BASE		(IO_PHYS + 0x2EC50000)
+#define DP_SEC_BASE		(IO_PHYS + 0x2EC10000)
+#define EDP_SEC_SIZE		(0x1000)
+#define DP_SEC_SIZE		(0x1000)
+
+/*******************************************************************************
  * EMI MPU related constants
  *******************************************************************************/
 #define EMI_MPU_BASE		(IO_PHYS + 0x00428000)
diff --git a/plat/mediatek/mt8196/plat_mmap.c b/plat/mediatek/mt8196/plat_mmap.c
index f7f819a..3d7be87 100644
--- a/plat/mediatek/mt8196/plat_mmap.c
+++ b/plat/mediatek/mt8196/plat_mmap.c
@@ -17,6 +17,10 @@
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(CPU_IDLE_SRAM_BASE, CPU_IDLE_SRAM_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DP_SEC_BASE, DP_SEC_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(EDP_SEC_BASE, EDP_SEC_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
 	{ 0 }
 };
 DECLARE_MTK_MMAP_REGIONS(plat_mmap);
diff --git a/plat/mediatek/mt8196/platform.mk b/plat/mediatek/mt8196/platform.mk
index fede717..062735b 100644
--- a/plat/mediatek/mt8196/platform.mk
+++ b/plat/mediatek/mt8196/platform.mk
@@ -25,6 +25,7 @@
 MODULES-y += $(MTK_PLAT)/common
 MODULES-y += $(MTK_PLAT)/lib/mtk_init
 MODULES-y += $(MTK_PLAT)/lib/pm
+MODULES-y += $(MTK_PLAT)/drivers/dp
 MODULES-y += $(MTK_PLAT)/drivers/mcusys
 MODULES-y += $(MTK_PLAT)/drivers/timer
 MODULES-y += $(MTK_PLAT)/helpers
diff --git a/plat/qemu/common/common.mk b/plat/qemu/common/common.mk
index ed95bc6..51497bd 100644
--- a/plat/qemu/common/common.mk
+++ b/plat/qemu/common/common.mk
@@ -8,6 +8,7 @@
 include common/fdt_wrappers.mk
 
 PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/		\
+				-I${PLAT_QEMU_COMMON_PATH}/		\
 				-I${PLAT_QEMU_COMMON_PATH}/include	\
 				-I${PLAT_QEMU_PATH}/include		\
 				-Iinclude/common/tbbr
@@ -65,7 +66,8 @@
 				${PLAT_QEMU_COMMON_PATH}/qemu_bl2_mem_params_desc.c	\
 				${PLAT_QEMU_COMMON_PATH}/qemu_image_load.c		\
 				common/desc_image_load.c		\
-				common/fdt_fixup.c
+				common/fdt_fixup.c			\
+				${FDT_WRAPPERS_SOURCES}
 
 BL31_SOURCES		+=	${QEMU_CPU_LIBS}				\
 				lib/semihosting/semihosting.c			\
diff --git a/plat/qemu/common/qemu_bl2_setup.c b/plat/qemu/common/qemu_bl2_setup.c
index c96e4b9..71f9cf7 100644
--- a/plat/qemu/common/qemu_bl2_setup.c
+++ b/plat/qemu/common/qemu_bl2_setup.c
@@ -22,9 +22,6 @@
 #include <lib/transfer_list.h>
 #include <lib/utils.h>
 #include <plat/common/platform.h>
-#if ENABLE_RME
-#include <qemu_pas_def.h>
-#endif
 
 #include "qemu_private.h"
 
@@ -84,8 +81,9 @@
 #endif
 	int ret;
 	void *fdt = (void *)(uintptr_t)ARM_PRELOADED_DTB_BASE;
+	void *dst = plat_qemu_dt_runtime_address();
 
-	ret = fdt_open_into(fdt, fdt, PLAT_QEMU_DT_MAX_SIZE);
+	ret = fdt_open_into(fdt, dst, PLAT_QEMU_DT_MAX_SIZE);
 	if (ret < 0) {
 		ERROR("Invalid Device Tree at %p: error %d\n", fdt, ret);
 		return;
@@ -150,54 +148,6 @@
 #endif
 }
 
-#if ENABLE_RME
-static void bl2_plat_gpt_setup(void)
-{
-	/*
-	 * The GPT library might modify the gpt regions structure to optimize
-	 * the layout, so the array cannot be constant.
-	 */
-	pas_region_t pas_regions[] = {
-		QEMU_PAS_ROOT,
-		QEMU_PAS_SECURE,
-		QEMU_PAS_GPTS,
-		QEMU_PAS_NS0,
-		QEMU_PAS_REALM,
-		QEMU_PAS_NS1,
-	};
-
-	/*
-	 * Initialize entire protected space to GPT_GPI_ANY. With each L0 entry
-	 * covering 1GB (currently the only supported option), then covering
-	 * 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(GPCCR_PPS_1TB, PLAT_QEMU_L0_GPT_BASE,
-			       PLAT_QEMU_L0_GPT_SIZE +
-			       PLAT_QEMU_GPT_BITLOCK_SIZE) < 0) {
-		ERROR("gpt_init_l0_tables() failed!\n");
-		panic();
-	}
-
-	/* Carve out defined PAS ranges. */
-	if (gpt_init_pas_l1_tables(GPCCR_PGS_4K,
-				   PLAT_QEMU_L1_GPT_BASE,
-				   PLAT_QEMU_L1_GPT_SIZE,
-				   pas_regions,
-				   (unsigned int)(sizeof(pas_regions) /
-						  sizeof(pas_region_t))) < 0) {
-		ERROR("gpt_init_pas_l1_tables() failed!\n");
-		panic();
-	}
-
-	INFO("Enabling Granule Protection Checks\n");
-	if (gpt_enable() < 0) {
-		ERROR("gpt_enable() failed!\n");
-		panic();
-	}
-}
-#endif
-
 void bl2_plat_arch_setup(void)
 {
 	const mmap_region_t bl_regions[] = {
@@ -220,9 +170,6 @@
 	/* BL2 runs in EL3 when RME enabled. */
 	assert(is_feat_rme_present());
 	enable_mmu_el3(0);
-
-	/* Initialise and enable granule protection after MMU. */
-	bl2_plat_gpt_setup();
 #else /* ENABLE_RME */
 
 #ifdef __aarch64__
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index 0a70cc2..e502e7b 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -11,6 +11,16 @@
 #include <lib/gpt_rme/gpt_rme.h>
 #include <lib/transfer_list.h>
 #include <plat/common/platform.h>
+#if ENABLE_RME
+#ifdef PLAT_qemu
+#include <qemu_pas_def.h>
+#elif PLAT_qemu_sbsa
+#include <qemu_sbsa_pas_def.h>
+#endif /* PLAT_qemu */
+#endif /* ENABLE_RME */
+#ifdef PLAT_qemu_sbsa
+#include <sbsa_platform.h>
+#endif
 
 #include "qemu_private.h"
 
@@ -63,7 +73,7 @@
 
 /* Platform names have to be lowercase. */
 #ifdef PLAT_qemu_sbsa
-	sip_svc_init();
+	sbsa_platform_init();
 #endif
 
 	/*
@@ -110,6 +120,100 @@
 	}
 }
 
+#if ENABLE_RME
+#if PLAT_qemu
+/*
+ * The GPT library might modify the gpt regions structure to optimize
+ * the layout, so the array cannot be constant.
+ */
+static pas_region_t pas_regions[] = {
+	QEMU_PAS_ROOT,
+	QEMU_PAS_SECURE,
+	QEMU_PAS_GPTS,
+	QEMU_PAS_NS0,
+	QEMU_PAS_REALM,
+	QEMU_PAS_NS1,
+};
+
+static inline void bl31_adjust_pas_regions(void) {}
+#elif PLAT_qemu_sbsa
+/*
+ * The GPT library might modify the gpt regions structure to optimize
+ * the layout, so the array cannot be constant.
+ */
+static pas_region_t pas_regions[] = {
+	QEMU_PAS_ROOT,
+	QEMU_PAS_SECURE,
+	QEMU_PAS_GPTS,
+	QEMU_PAS_REALM,
+	QEMU_PAS_NS0,
+};
+
+static void bl31_adjust_pas_regions(void)
+{
+	uint64_t base_addr = 0, total_size = 0;
+	struct platform_memory_data data;
+	uint32_t node;
+
+	/*
+	 * The amount of memory supported by the SBSA platform is dynamic
+	 * and dependent on user input.  Since the configuration of the GPT
+	 * needs to reflect the system memory, QEMU_PAS_NS0 needs to be set
+	 * based on the information found in the device tree.
+	 */
+
+	for (node = 0; node < sbsa_platform_num_memnodes(); node++) {
+		data = sbsa_platform_memory_node(node);
+
+		if (data.nodeid == 0) {
+			base_addr = data.addr_base;
+		}
+
+		total_size += data.addr_size;
+	}
+
+	 /* Index '4' correspond to QEMU_PAS_NS0, see pas_regions[] above */
+	pas_regions[4].base_pa = base_addr;
+	pas_regions[4].size = total_size;
+}
+#endif /* PLAT_qemu */
+
+static void bl31_plat_gpt_setup(void)
+{
+	/*
+	 * Initialize entire protected space to GPT_GPI_ANY. With each L0 entry
+	 * covering 1GB (currently the only supported option), then covering
+	 * 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) {
+		ERROR("gpt_init_l0_tables() failed!\n");
+		panic();
+	}
+
+	bl31_adjust_pas_regions();
+
+	/* Carve out defined PAS ranges. */
+	if (gpt_init_pas_l1_tables(GPCCR_PGS_4K,
+				   PLAT_QEMU_L1_GPT_BASE,
+				   PLAT_QEMU_L1_GPT_SIZE,
+				   pas_regions,
+				   (unsigned int)(sizeof(pas_regions) /
+						  sizeof(pas_region_t))) < 0) {
+		ERROR("gpt_init_pas_l1_tables() failed!\n");
+		panic();
+	}
+
+	INFO("Enabling Granule Protection Checks\n");
+	if (gpt_enable() < 0) {
+		ERROR("gpt_enable() failed!\n");
+		panic();
+	}
+}
+#endif
+
 void bl31_plat_arch_setup(void)
 {
 	const mmap_region_t bl_regions[] = {
@@ -131,6 +235,9 @@
 	enable_mmu_el3(0);
 
 #if ENABLE_RME
+	/* Initialise and enable granule protection after MMU. */
+	bl31_plat_gpt_setup();
+
 	/*
 	 * Initialise Granule Protection library and enable GPC for the primary
 	 * processor. The tables have already been initialized by a previous BL
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
index 9ccb2c8..0bfb126 100644
--- a/plat/qemu/common/qemu_common.c
+++ b/plat/qemu/common/qemu_common.c
@@ -16,6 +16,9 @@
 #if ENABLE_RME
 #include <services/rmm_core_manifest.h>
 #endif
+#ifdef PLAT_qemu_sbsa
+#include <sbsa_platform.h>
+#endif
 
 #include <plat/common/platform.h>
 #include "qemu_private.h"
@@ -224,12 +227,42 @@
 	return (size_t)RMM_SHARED_SIZE;
 }
 
+#ifdef PLAT_qemu
+static uint32_t plat_get_num_memnodes(void)
+{
+	return 1;
+}
+
+static void plat_get_memory_node(int index, struct ns_dram_bank *bank_ptr)
+{
+	(void) index;
+	bank_ptr->base = NS_DRAM0_BASE;
+	bank_ptr->size = NS_DRAM0_SIZE;
+}
+#elif PLAT_qemu_sbsa
+static uint32_t plat_get_num_memnodes(void)
+{
+	return sbsa_platform_num_memnodes();
+}
+
+static void plat_get_memory_node(int index, struct ns_dram_bank *bank_ptr)
+{
+	struct platform_memory_data data = {0, 0, 0};
+
+	if (index < sbsa_platform_num_memnodes()) {
+		data = sbsa_platform_memory_node(index);
+	}
+
+	bank_ptr->base = data.addr_base;
+	bank_ptr->size = data.addr_size;
+}
+#endif /* PLAT_qemu */
+
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest)
 {
+	int i, last;
 	uint64_t checksum;
-	uintptr_t base;
-	uint64_t size;
-	size_t num_banks = 1;
+	size_t num_banks = plat_get_num_memnodes();
 	size_t num_consoles = 1;
 	struct ns_dram_bank *bank_ptr;
 	struct console_info *console_ptr;
@@ -300,11 +333,28 @@
 	/* Calculate checksum of plat_dram structure */
 	checksum = num_banks + (uint64_t)bank_ptr;
 
-	base = NS_DRAM0_BASE;
-	size = NS_DRAM0_SIZE;
-	bank_ptr[0].base = base;
-	bank_ptr[0].size = size;
-	checksum += base + size;
+	/*
+	 * In the TF-A, NUMA nodes (if present) are stored in descending
+	 * order, i.e:
+	 *
+	 * INFO:    RAM 0: node-id: 1, address: 0x10080000000 - 0x101ffffffff
+	 * INFO:    RAM 1: node-id: 0, address: 0x10043000000 - 0x1007fffffff
+	 *
+	 * The RMM expects the memory banks to be presented in ascending order:
+	 *
+	 * INFO:    RAM 1: node-id: 0, address: 0x10043000000 - 0x1007fffffff
+	 * INFO:    RAM 0: node-id: 1, address: 0x10080000000 - 0x101ffffffff
+	 *
+	 * As such, go through the NUMA nodes one by one and fill out
+	 * @bank_ptr[] starting from the end.  When NUMA nodes are not present
+	 * there is only one memory bank and none of the above matters.
+	 */
+	last = num_banks - 1;
+	for (i = 0; i < num_banks; i++) {
+		plat_get_memory_node(i, &bank_ptr[last]);
+		checksum += bank_ptr[last].base + bank_ptr[last].size;
+		last--;
+	}
 
 	/* Checksum must be 0 */
 	manifest->plat_dram.checksum = ~checksum + 1UL;
@@ -332,3 +382,25 @@
 	return 0;
 }
 #endif  /* ENABLE_RME */
+
+/**
+ * plat_qemu_dt_runtime_address() - Get the final DT location in RAM
+ *
+ * When support is enabled on SBSA, the device tree is relocated from its
+ * original place at the beginning of the NS RAM to after the RMM.  This
+ * function returns the address of the final location in RAM of the device
+ * tree.  See function update_dt() in qemu_bl2_setup.c
+ *
+ * Return: The address of the final location in RAM of the device tree
+ */
+#if (ENABLE_RME && PLAT_qemu_sbsa)
+void *plat_qemu_dt_runtime_address(void)
+{
+	return (void *)(uintptr_t)PLAT_QEMU_DT_BASE;
+}
+#else
+void *plat_qemu_dt_runtime_address(void)
+{
+	return (void *)(uintptr_t)ARM_PRELOADED_DTB_BASE;
+}
+#endif /* (ENABLE_RME && PLAT_qemu_sbsa) */
diff --git a/plat/qemu/common/qemu_private.h b/plat/qemu/common/qemu_private.h
index 25b14e2..046cb78 100644
--- a/plat/qemu/common/qemu_private.h
+++ b/plat/qemu/common/qemu_private.h
@@ -16,11 +16,9 @@
 			    uintptr_t load_addr);
 unsigned int plat_qemu_calc_core_pos(u_register_t mpidr);
 const mmap_region_t *plat_qemu_get_mmap(void);
+void *plat_qemu_dt_runtime_address(void);
 
 void qemu_console_init(void);
-#ifdef PLAT_qemu_sbsa
-void sip_svc_init(void);
-#endif
 
 void plat_qemu_gic_init(void);
 void qemu_pwr_gic_on_finish(void);
diff --git a/plat/qemu/qemu/include/qemu_pas_def.h b/plat/qemu/qemu/include/qemu_pas_def.h
index bcbea21..30934f0 100644
--- a/plat/qemu/qemu/include/qemu_pas_def.h
+++ b/plat/qemu/qemu/include/qemu_pas_def.h
@@ -102,6 +102,9 @@
 							       QEMU_PAS_RMM_SHARED_SIZE, \
 							       GPT_GPI_REALM)
 
+/* Cover 1TB with L0GTP */
+#define PLATFORM_GPCCR_PPS		GPCCR_PPS_1TB
+
 /* GPT Configuration options */
 #define PLATFORM_L0GPTSZ		GPCCR_L0GPTSZ_30BITS
 
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index 0d4cdb8..70e9faf 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -115,8 +115,7 @@
     include drivers/auth/mbedtls/mbedtls_crypto.mk
 endif
 
-BL2_SOURCES		+=	${FDT_WRAPPERS_SOURCES}					\
-				common/uuid.c
+BL2_SOURCES		+=	common/uuid.c
 
 ifeq ($(add-lib-optee),yes)
 BL2_SOURCES		+=	lib/optee/optee_utils.c
diff --git a/plat/qemu/qemu_sbsa/include/platform_def.h b/plat/qemu/qemu_sbsa/include/platform_def.h
index d230095..06e8abf 100644
--- a/plat/qemu/qemu_sbsa/include/platform_def.h
+++ b/plat/qemu/qemu_sbsa/include/platform_def.h
@@ -66,6 +66,9 @@
  */
 #define PLAT_MAX_MEM_NODES	128
 
+/* Where QEMU starts the NS RAM */
+#define PLAT_QEMU_DRAM0_BASE	0x10000000000ULL
+
 /*
  * Partition memory into secure ROM, non-secure DRAM, secure "SRAM",
  * and secure DRAM.
@@ -73,7 +76,12 @@
 #define SEC_ROM_BASE			0x00000000
 #define SEC_ROM_SIZE			0x00020000
 
-#define NS_DRAM0_BASE			0x10000000000ULL
+/*
+ * When the RME extension is enabled, the base of the NS RAM is shifted after
+ * RMM.
+ */
+#define NS_DRAM0_BASE			(PLAT_QEMU_DRAM0_BASE + \
+					NS_DRAM0_BASE_OFFSET)
 #define NS_DRAM0_SIZE			0x00020000000
 
 #define SEC_SRAM_BASE			0x20000000
@@ -121,7 +129,8 @@
 #define BL1_RO_BASE			SEC_ROM_BASE
 #define BL1_RO_LIMIT			(SEC_ROM_BASE + SEC_ROM_SIZE)
 #define BL1_RW_BASE			(BL1_RW_LIMIT - BL1_SIZE)
-#define BL1_RW_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+#define BL1_RW_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE - \
+					 RME_GPT_DRAM_SIZE)
 
 /*
  * BL2 specific defines.
@@ -139,7 +148,7 @@
  * Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the
  * current BL3-1 debug size plus a little space for growth.
  */
-#define BL31_SIZE			0x300000
+#define BL31_SIZE			0x400000
 #define BL31_BASE			(BL31_LIMIT - BL31_SIZE)
 #define BL31_LIMIT			(BL1_RW_BASE)
 #define BL31_PROGBITS_LIMIT		BL1_RW_BASE
@@ -154,8 +163,8 @@
 #define BL32_SRAM_LIMIT			BL2_BASE
 
 #define BL32_MEM_BASE			BL_RAM_BASE
-#define BL32_MEM_SIZE			(BL_RAM_SIZE - BL1_SIZE - \
-					BL2_SIZE - BL31_SIZE)
+#define BL32_MEM_SIZE			(BL_RAM_SIZE - RME_GPT_DRAM_SIZE - \
+					BL1_SIZE - BL2_SIZE - BL31_SIZE)
 #define BL32_BASE			BL32_SRAM_BASE
 #define BL32_LIMIT			BL32_SRAM_LIMIT
 
@@ -167,6 +176,9 @@
 #if SPM_MM
 #define MAX_MMAP_REGIONS		12
 #define MAX_XLAT_TABLES			12
+#elif ENABLE_RME
+#define MAX_MMAP_REGIONS		14
+#define MAX_XLAT_TABLES			14
 #else
 #define MAX_MMAP_REGIONS		11
 #define MAX_XLAT_TABLES			11
@@ -205,7 +217,7 @@
 #define QEMU_FLASH1_SIZE		0x10000000
 
 #define PLAT_QEMU_FIP_BASE		BL1_SIZE
-#define PLAT_QEMU_FIP_MAX_SIZE		0x00400000
+#define PLAT_QEMU_FIP_MAX_SIZE		(QEMU_FLASH0_SIZE - BL1_SIZE)
 
 /* This is map from GIC_DIST up to last CPU (255) GIC_REDISTR */
 #define DEVICE0_BASE			0x40000000
@@ -377,4 +389,105 @@
 #define QEMU_PRI_BITS		2
 #define PLAT_SP_PRI		0x20
 
+#if !ENABLE_RME
+#define RME_GPT_DRAM_SIZE	0
+#define NS_DRAM0_BASE_OFFSET	0
+#else /* !ENABLE_RME */
+/*
+ * SBSA RAM starts at 1TB and we support up to 1TB of RAM.  As such we
+ * have 2TB of physical address space to cover.  Since the GPT size can be
+ * 4GB, 64GB, 1TB, 4TB and so on, we need to select 4GB.  Note that it is
+ * possible to support more than 1TB of RAM but that will take more room in
+ * secure memory due to the L1 GPTES.  See PLAT_QEMU_L1_GPT_SIZE for details.
+ *
+ * 4TB / 1GB == 4096 GPTEs
+ * 4096 * 8 (bytes per GPTE) == 32768 i.e 8 pages
+ */
+#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))
+
+#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
+ * one more L1GPT to cover the other physical address spaces (see pas_regions[]
+ * in qemu_bl31_setup.c), we need a total of 1025 L1GPTs.  Each L1GPT is 131072
+ * bytes, so we need 1025 * 131072 bytes = 0x8020000 of RAM to hold the L1GPTS.
+ */
+#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)
+
+#ifndef __ASSEMBLER__
+/* L0 table greater than 4KB must be naturally aligned */
+CASSERT((PLAT_QEMU_L0_GPT_BASE & (PLAT_QEMU_L0_GPT_SIZE - 1)) == 0,
+	assert_l0_gpt_naturally_aligned);
+#endif
+
+/* Reserved some DRAM space for RMM (1072MB) */
+#define REALM_DRAM_BASE			PLAT_QEMU_DRAM0_BASE
+#define REALM_DRAM_SIZE			0x43000000
+
+#define PLAT_QEMU_RMM_SIZE		(REALM_DRAM_SIZE - RMM_SHARED_SIZE)
+#define PLAT_QEMU_RMM_SHARED_SIZE	(PAGE_SIZE)	/* 4KB */
+
+#define RMM_BASE			(REALM_DRAM_BASE)
+#define RMM_LIMIT			(RMM_BASE + PLAT_QEMU_RMM_SIZE)
+#define RMM_SHARED_BASE			(RMM_LIMIT)
+#define RMM_SHARED_SIZE			PLAT_QEMU_RMM_SHARED_SIZE
+
+#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),	\
+					MT_MEMORY | MT_RW | EL3_PAS)
+
+#define MAP_GPT_L1_REGION		MAP_REGION_FLAT(		\
+					PLAT_QEMU_L1_GPT_BASE,		\
+					PLAT_QEMU_L1_GPT_SIZE,		\
+					MT_MEMORY | MT_RW | EL3_PAS)
+/*
+ * We add the RMM_SHARED size to RMM mapping to map the region as a block.
+ * Else we end up requiring more pagetables in BL2 for ROMLIB build.
+ */
+#define MAP_RMM_DRAM			MAP_REGION_FLAT(		\
+					RMM_BASE,			\
+					(PLAT_QEMU_RMM_SIZE +		\
+					 RMM_SHARED_SIZE),		\
+					MT_MEMORY | MT_RW | MT_REALM)
+
+#define MAP_RMM_SHARED_MEM		MAP_REGION_FLAT(		\
+					RMM_SHARED_BASE,		\
+					RMM_SHARED_SIZE,		\
+					MT_MEMORY | MT_RW | MT_REALM)
+
+/* When RME is enabled, the base of NS DRAM is moved forward after the RMM */
+#define NS_DRAM0_BASE_OFFSET	REALM_DRAM_SIZE
+#endif /* !ENABLE_RME */
+
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h b/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h
new file mode 100644
index 0000000..c73a162
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/include/qemu_sbsa_pas_def.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2024-2025, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QEMU_PAS_DEF_H
+#define QEMU_PAS_DEF_H
+
+#include <lib/gpt_rme/gpt_rme.h>
+#include "platform_def.h"
+
+/*****************************************************************************
+ * PAS regions used to initialize the Granule Protection Table (GPT)
+ ****************************************************************************/
+
+/* EL3 SRAM */
+#define QEMU_PAS_ROOT_BASE	(BL32_MEM_BASE + BL32_MEM_SIZE)
+#define QEMU_PAS_ROOT_SIZE	(BL_RAM_SIZE - \
+				 (BL32_MEM_SIZE + RME_GPT_DRAM_SIZE))
+
+/* Secure DRAM */
+#define QEMU_PAS_SEC_BASE	BL32_MEM_BASE /* BL32_SRAM_BASE */
+#define QEMU_PAS_SEC_SIZE	BL32_MEM_SIZE
+
+/* GPTs */
+#define QEMU_PAS_GPT_BASE	RME_GPT_DRAM_BASE /* PLAT_QEMU_L0_GPT_BASE */
+#define QEMU_PAS_GPT_SIZE	RME_GPT_DRAM_SIZE
+
+/* RMM */
+#define QEMU_PAS_RMM_BASE	RMM_BASE
+#define QEMU_PAS_RMM_SIZE	PLAT_QEMU_RMM_SIZE
+
+/* Shared area between EL3 and RMM */
+#define QEMU_PAS_RMM_SHARED_BASE	RMM_SHARED_BASE
+#define QEMU_PAS_RMM_SHARED_SIZE	RMM_SHARED_SIZE
+
+#define QEMU_PAS_ROOT		GPT_MAP_REGION_GRANULE(QEMU_PAS_ROOT_BASE, \
+						       QEMU_PAS_ROOT_SIZE, \
+						       GPT_GPI_ROOT)
+
+#define QEMU_PAS_SECURE		GPT_MAP_REGION_GRANULE(QEMU_PAS_SEC_BASE, \
+						       QEMU_PAS_SEC_SIZE, \
+						       GPT_GPI_SECURE)
+
+#define QEMU_PAS_GPTS		GPT_MAP_REGION_GRANULE(QEMU_PAS_GPT_BASE, \
+						       QEMU_PAS_GPT_SIZE, \
+						       GPT_GPI_ROOT)
+
+/*
+ * NS0 base address and size are fetched from the DT at runtime.
+ * See bl31_adjust_pas_regions() for details
+ */
+#define QEMU_PAS_NS0		GPT_MAP_REGION_GRANULE(0, 0, GPT_GPI_NS)
+
+#define QEMU_PAS_REALM		GPT_MAP_REGION_GRANULE(QEMU_PAS_RMM_BASE, \
+					       QEMU_PAS_RMM_SIZE + \
+					       QEMU_PAS_RMM_SHARED_SIZE, \
+					       GPT_GPI_REALM)
+
+/* Cover 4TB with L0GTP */
+#define PLATFORM_GPCCR_PPS	GPCCR_PPS_4TB
+
+/* GPT Configuration options */
+#define PLATFORM_L0GPTSZ	GPCCR_L0GPTSZ_30BITS
+
+#endif /* QEMU_PAS_DEF_H */
diff --git a/plat/qemu/qemu_sbsa/include/sbsa_platform.h b/plat/qemu/qemu_sbsa/include/sbsa_platform.h
new file mode 100644
index 0000000..a3b3ea1
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/include/sbsa_platform.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024-2025, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SBSA_PLATFORM_H
+#define SBSA_PLATFORM_H
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+struct platform_cpu_data {
+	uint32_t nodeid;
+	uint32_t mpidr;
+};
+
+struct platform_memory_data {
+	uint32_t nodeid;
+	uint64_t addr_base;
+	uint64_t addr_size;
+};
+
+/*
+ * sockets: the number of sockets on sbsa-ref platform.
+ * clusters: the number of clusters in one socket.
+ * cores: the number of cores in one cluster.
+ * threads: the number of threads in one core.
+ */
+struct platform_cpu_topology {
+	uint32_t sockets;
+	uint32_t clusters;
+	uint32_t cores;
+	uint32_t threads;
+};
+
+struct qemu_platform_info {
+	uint32_t num_cpus;
+	uint32_t num_memnodes;
+	struct platform_cpu_data cpu[PLATFORM_CORE_COUNT];
+	struct platform_cpu_topology cpu_topo;
+	struct platform_memory_data memory[PLAT_MAX_MEM_NODES];
+};
+
+void sbsa_platform_init(void);
+int sbsa_platform_version_major(void);
+int sbsa_platform_version_minor(void);
+uint32_t sbsa_platform_num_cpus(void);
+uint32_t sbsa_platform_num_memnodes(void);
+uint64_t sbsa_platform_gic_its_addr(void);
+struct platform_cpu_data sbsa_platform_cpu_node(uint64_t index);
+struct platform_memory_data sbsa_platform_memory_node(uint64_t index);
+struct platform_cpu_topology sbsa_platform_cpu_topology(void);
+
+#endif /* SBSA_PLATFORM_H */
diff --git a/plat/qemu/qemu_sbsa/platform.mk b/plat/qemu/qemu_sbsa/platform.mk
index 528e093..8ec3a82 100644
--- a/plat/qemu/qemu_sbsa/platform.mk
+++ b/plat/qemu/qemu_sbsa/platform.mk
@@ -29,8 +29,6 @@
 $(eval $(call add_define,QEMU_LOAD_BL32))
 endif
 
-BL2_SOURCES		+=	$(LIBFDT_SRCS)
-
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk
 
@@ -38,6 +36,7 @@
 				plat/common/plat_gicv3.c
 
 BL31_SOURCES		+=	${PLAT_QEMU_PATH}/sbsa_gic.c 			\
+				${PLAT_QEMU_PATH}/sbsa_platform.c		\
 				${PLAT_QEMU_PATH}/sbsa_pm.c			\
 				${PLAT_QEMU_PATH}/sbsa_sip_svc.c		\
 				${PLAT_QEMU_PATH}/sbsa_topology.c
@@ -61,5 +60,5 @@
 $(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33))
 $(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33))
 
-ARM_PRELOADED_DTB_BASE := PLAT_QEMU_DT_BASE
+ARM_PRELOADED_DTB_BASE := PLAT_QEMU_DRAM0_BASE
 $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
diff --git a/plat/qemu/qemu_sbsa/sbsa_platform.c b/plat/qemu/qemu_sbsa/sbsa_platform.c
new file mode 100644
index 0000000..8c8d632
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/sbsa_platform.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2024-2025, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+
+#include <sbsa_platform.h>
+
+#include "qemu_private.h"
+
+/* default platform version is 0.0 */
+static int platform_version_major;
+static int platform_version_minor;
+
+static uint64_t gic_its_addr;
+static struct qemu_platform_info dynamic_platform_info;
+
+void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base);
+
+/*
+ * QEMU provides us with minimal information about hardware platform using
+ * minimalistic DeviceTree. This is not a Linux DeviceTree. It is not even
+ * a firmware DeviceTree.
+ *
+ * It is information passed from QEMU to describe the information a hardware
+ * platform would have other mechanisms to discover at runtime, that are
+ * affected by the QEMU command line.
+ *
+ * Ultimately this device tree will be replaced by IPC calls to an emulated SCP.
+ * And when we do that, we won't then have to rewrite Normal world firmware to
+ * cope.
+ */
+
+static void read_cpu_topology_from_dt(void *dtb)
+{
+	int node;
+
+	/*
+	 * QEMU gives us this DeviceTree node when we config:
+	 * -smp 16,sockets=2,clusters=2,cores=2,threads=2
+	 *
+	 * topology {
+	 *	threads = <0x02>;
+	 *	cores = <0x02>;
+	 *	clusters = <0x02>;
+	 *	sockets = <0x02>;
+	 * };
+	 */
+
+	node = fdt_path_offset(dtb, "/cpus/topology");
+	if (node > 0) {
+		dynamic_platform_info.cpu_topo.sockets =
+			fdt_read_uint32_default(dtb, node, "sockets", 0);
+		dynamic_platform_info.cpu_topo.clusters =
+			fdt_read_uint32_default(dtb, node, "clusters", 0);
+		dynamic_platform_info.cpu_topo.cores =
+			fdt_read_uint32_default(dtb, node, "cores", 0);
+		dynamic_platform_info.cpu_topo.threads =
+			fdt_read_uint32_default(dtb, node, "threads", 0);
+	}
+
+	INFO("Cpu topology: sockets: %d, clusters: %d, cores: %d, threads: %d\n",
+		dynamic_platform_info.cpu_topo.sockets,
+		dynamic_platform_info.cpu_topo.clusters,
+		dynamic_platform_info.cpu_topo.cores,
+		dynamic_platform_info.cpu_topo.threads);
+}
+
+static void read_cpuinfo_from_dt(void *dtb)
+{
+	int node;
+	int prev;
+	int cpu = 0;
+	uintptr_t mpidr;
+
+	/*
+	 * QEMU gives us this DeviceTree node:
+	 * numa-node-id entries are only when NUMA config is used
+	 *
+	 *  cpus {
+	 *	#size-cells = <0x00>;
+	 *	#address-cells = <0x02>;
+	 *
+	 *	cpu@0 {
+	 *		numa-node-id = <0x00>;
+	 *		reg = <0x00 0x00>;
+	 *	};
+	 *
+	 *	cpu@1 {
+	 *		numa-node-id = <0x03>;
+	 *		reg = <0x00 0x01>;
+	 *	};
+	 *  };
+	 */
+	node = fdt_path_offset(dtb, "/cpus");
+	if (node < 0) {
+		ERROR("No information about cpus in DeviceTree.\n");
+		panic();
+	}
+
+	/*
+	 * QEMU numbers cpus from 0 and there can be /cpus/cpu-map present so we
+	 * cannot use fdt_first_subnode() here
+	 */
+	node = fdt_path_offset(dtb, "/cpus/cpu@0");
+
+	while (node > 0) {
+		if (fdt_getprop(dtb, node, "reg", NULL)) {
+			fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL);
+		} else {
+			ERROR("Incomplete information for cpu %d in DeviceTree.\n", cpu);
+			panic();
+		}
+
+		dynamic_platform_info.cpu[cpu].mpidr = mpidr;
+		dynamic_platform_info.cpu[cpu].nodeid =
+			fdt_read_uint32_default(dtb, node, "numa-node-id", 0);
+
+		INFO("CPU %d: node-id: %d, mpidr: %ld\n", cpu,
+				dynamic_platform_info.cpu[cpu].nodeid, mpidr);
+
+		cpu++;
+
+		prev = node;
+		node = fdt_next_subnode(dtb, prev);
+	}
+
+	dynamic_platform_info.num_cpus = cpu;
+	INFO("Found %d cpus\n", dynamic_platform_info.num_cpus);
+
+	read_cpu_topology_from_dt(dtb);
+}
+
+static void read_meminfo_from_dt(void *dtb)
+{
+	const fdt32_t *prop;
+	const char *type;
+	int prev, node;
+	int len;
+	uint32_t memnode = 0;
+	uint32_t higher_value, lower_value;
+	uint64_t cur_base, cur_size;
+
+	/*
+	 * QEMU gives us this DeviceTree node:
+	 *
+	 *	memory@100c0000000 {
+	 *		numa-node-id = <0x01>;
+	 *		reg = <0x100 0xc0000000 0x00 0x40000000>;
+	 *		device_type = "memory";
+	 *	};
+	 *
+	 *	memory@10000000000 {
+	 *		numa-node-id = <0x00>;
+	 *		reg = <0x100 0x00 0x00 0xc0000000>;
+	 *		device_type = "memory";
+	 *	}
+	 */
+
+	for (prev = 0;; prev = node) {
+		node = fdt_next_node(dtb, prev, NULL);
+		if (node < 0) {
+			break;
+		}
+
+		type = fdt_getprop(dtb, node, "device_type", &len);
+		if (type && strncmp(type, "memory", len) == 0) {
+			dynamic_platform_info.memory[memnode].nodeid =
+				fdt_read_uint32_default(dtb, node, "numa-node-id", 0);
+
+			/*
+			 * Get the 'reg' property of this node and
+			 * assume two 8 bytes for base and size.
+			 */
+			prop = fdt_getprop(dtb, node, "reg", &len);
+			if (prop != 0 && len == (2 * sizeof(int64_t))) {
+				higher_value = fdt32_to_cpu(*prop);
+				lower_value = fdt32_to_cpu(*(prop + 1));
+				cur_base = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32);
+
+				higher_value = fdt32_to_cpu(*(prop + 2));
+				lower_value = fdt32_to_cpu(*(prop + 3));
+				cur_size = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32);
+
+				dynamic_platform_info.memory[memnode].addr_base = cur_base;
+				dynamic_platform_info.memory[memnode].addr_size = cur_size;
+
+				INFO("RAM %d: node-id: %d, address: 0x%lx - 0x%lx\n",
+					memnode,
+					dynamic_platform_info.memory[memnode].nodeid,
+					dynamic_platform_info.memory[memnode].addr_base,
+					dynamic_platform_info.memory[memnode].addr_base +
+					dynamic_platform_info.memory[memnode].addr_size - 1);
+			}
+
+			memnode++;
+		}
+	}
+
+	dynamic_platform_info.num_memnodes = memnode;
+}
+
+static void read_platform_config_from_dt(void *dtb)
+{
+	int node;
+	const fdt64_t *data;
+	int err;
+	uintptr_t gicd_base;
+	uintptr_t gicr_base;
+
+	/*
+	 * QEMU gives us this DeviceTree node:
+	 *
+	 * intc {
+	 *	 reg = < 0x00 0x40060000 0x00 0x10000
+	 *		 0x00 0x40080000 0x00 0x4000000>;
+	 *       its {
+	 *               reg = <0x00 0x44081000 0x00 0x20000>;
+	 *       };
+	 * };
+	 */
+	node = fdt_path_offset(dtb, "/intc");
+	if (node < 0) {
+		return;
+	}
+
+	data = fdt_getprop(dtb, node, "reg", NULL);
+	if (data == NULL) {
+		return;
+	}
+
+	err = fdt_get_reg_props_by_index(dtb, node, 0, &gicd_base, NULL);
+	if (err < 0) {
+		ERROR("Failed to read GICD reg property of GIC node\n");
+		return;
+	}
+	INFO("GICD base = 0x%lx\n", gicd_base);
+
+	err = fdt_get_reg_props_by_index(dtb, node, 1, &gicr_base, NULL);
+	if (err < 0) {
+		ERROR("Failed to read GICR reg property of GIC node\n");
+		return;
+	}
+	INFO("GICR base = 0x%lx\n", gicr_base);
+
+	sbsa_set_gic_bases(gicd_base, gicr_base);
+
+	node = fdt_path_offset(dtb, "/intc/its");
+	if (node < 0) {
+		return;
+	}
+
+	err = fdt_get_reg_props_by_index(dtb, node, 0, &gic_its_addr, NULL);
+	if (err < 0) {
+		ERROR("Failed to read GICI reg property of GIC node\n");
+		return;
+	}
+	INFO("GICI base = 0x%lx\n", gic_its_addr);
+}
+
+static void read_platform_version(void *dtb)
+{
+	int node;
+
+	node = fdt_path_offset(dtb, "/");
+	if (node >= 0) {
+		platform_version_major =
+			fdt_read_uint32_default(dtb, node, "machine-version-major", 0);
+		platform_version_minor =
+			fdt_read_uint32_default(dtb, node, "machine-version-minor", 0);
+	}
+}
+
+#if !ENABLE_RME
+static int set_system_memory_base(void *dtb, uintptr_t new_base)
+{
+	(void)dtb;
+	(void)new_base;
+
+	return 0;
+}
+#else /* !ENABLE_RME */
+static int set_system_memory_base(void *dtb, uintptr_t new_base)
+{
+	uint64_t cur_base, cur_size, new_size, delta;
+	int len, prev, node, ret;
+	const fdt32_t *prop;
+	uint32_t node_id;
+	const char *type;
+	fdt64_t new[2];
+
+	/*
+	 * QEMU gives us this DeviceTree node:
+	 *
+	 *	memory@100c0000000 {
+	 *		numa-node-id = <0x01>;
+	 *		reg = <0x100 0xc0000000 0x00 0x40000000>;
+	 *		device_type = "memory";
+	 *	};
+	 *
+	 *	memory@10000000000 {
+	 *		numa-node-id = <0x00>;
+	 *		reg = <0x100 0x00 0x00 0xc0000000>;
+	 *		device_type = "memory";
+	 *	}
+	 */
+
+	for (prev = 0;; prev = node) {
+		node = fdt_next_node(dtb, prev, NULL);
+		if (node < 0) {
+			return node;
+		}
+
+		type = fdt_getprop(dtb, node, "device_type", &len);
+		if (type && strncmp(type, "memory", len) == 0) {
+
+			/*
+			 * We are looking for numa node 0, i.e the start of the
+			 * system memory.  If a "numa-node-id" doesn't exists we
+			 * take the first one.
+			 */
+			node_id = fdt_read_uint32_default(dtb, node,
+							  "numa-node-id", 0);
+
+			if (node_id == 0) {
+				break;
+			}
+		}
+	}
+
+	/*
+	 * Get the 'reg' property of this node and
+	 * assume two 8 bytes for base and size.
+	 */
+	prop = fdt_getprop(dtb, node, "reg", &len);
+	if (!prop || len < 0) {
+		return len;
+	}
+
+	if (len != (2 * sizeof(uint64_t))) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	ret = fdt_get_reg_props_by_index(dtb, node, 0, &cur_base, &cur_size);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * @cur_base is the base of the NS RAM given to us by QEMU, we can't
+	 * go lower than that.
+	 */
+	if (new_base < cur_base) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	if (new_base == cur_base) {
+		return 0;
+	}
+
+	/*
+	 * The new base is higher than the base set by QEMU, i.e we are moving
+	 * the base memory up and shrinking the size.
+	 */
+	delta = (size_t)(new_base - cur_base);
+
+	/*
+	 * Make sure the new base is still within the base memory node, i.e
+	 * the base memory node is big enough for the RMM.
+	 */
+	if (delta >= cur_size) {
+		ERROR("Not enough space in base memory node for RMM\n");
+		return -FDT_ERR_BADVALUE;
+	}
+
+	new_size = cur_size - delta;
+
+	new[0] = cpu_to_fdt64(new_base);
+	new[1] = cpu_to_fdt64(new_size);
+
+	ret = fdt_setprop(dtb, node, "reg", new, len);
+	if (ret < 0) {
+		return ret;
+	}
+
+	return fdt_pack(dtb);
+}
+#endif /* !ENABLE_RME */
+
+void sbsa_platform_init(void)
+{
+	/* Read DeviceTree data before MMU is enabled */
+
+	void *dtb = plat_qemu_dt_runtime_address();
+	int err;
+
+	err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE);
+	if (err < 0) {
+		ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
+		return;
+	}
+
+	err = fdt_check_header(dtb);
+	if (err < 0) {
+		ERROR("Invalid DTB file passed\n");
+		return;
+	}
+
+	read_platform_version(dtb);
+	INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor);
+
+	if (set_system_memory_base(dtb, NS_DRAM0_BASE)) {
+		ERROR("Failed to set system memory in Device Tree\n");
+		return;
+	}
+
+	read_platform_config_from_dt(dtb);
+	read_cpuinfo_from_dt(dtb);
+	read_meminfo_from_dt(dtb);
+}
+
+int sbsa_platform_version_major(void)
+{
+	return platform_version_major;
+}
+
+int sbsa_platform_version_minor(void)
+{
+	return platform_version_minor;
+}
+
+uint32_t sbsa_platform_num_cpus(void)
+{
+	return dynamic_platform_info.num_cpus;
+}
+
+uint32_t sbsa_platform_num_memnodes(void)
+{
+	return dynamic_platform_info.num_memnodes;
+}
+
+uint64_t sbsa_platform_gic_its_addr(void)
+{
+	return gic_its_addr;
+}
+
+struct platform_cpu_data sbsa_platform_cpu_node(uint64_t index)
+{
+	return dynamic_platform_info.cpu[index];
+}
+
+struct platform_memory_data sbsa_platform_memory_node(uint64_t index)
+{
+	return dynamic_platform_info.memory[index];
+}
+
+struct platform_cpu_topology sbsa_platform_cpu_topology(void)
+{
+	return dynamic_platform_info.cpu_topo;
+}
diff --git a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
index 83e66f3..839bb1c 100644
--- a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
+++ b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
@@ -6,14 +6,10 @@
 
 #include <assert.h>
 
-#include <common/fdt_wrappers.h>
 #include <common/runtime_svc.h>
-#include <libfdt.h>
 #include <smccc_helpers.h>
 
-/* default platform version is 0.0 */
-static int platform_version_major;
-static int platform_version_minor;
+#include <sbsa_platform.h>
 
 #define SMC_FASTCALL       0x80000000
 #define SMC64_FUNCTION     (SMC_FASTCALL   | 0x40000000)
@@ -34,326 +30,10 @@
 #define SIP_SVC_GET_MEMORY_NODE_COUNT SIP_FUNCTION_ID(300)
 #define SIP_SVC_GET_MEMORY_NODE SIP_FUNCTION_ID(301)
 
-static uint64_t gic_its_addr;
-
-typedef struct {
-	uint32_t nodeid;
-	uint32_t mpidr;
-} cpu_data;
-
-typedef struct{
-	uint32_t nodeid;
-	uint64_t addr_base;
-	uint64_t addr_size;
-} memory_data;
-
-/*
- * sockets: the number of sockets on sbsa-ref platform.
- * clusters: the number of clusters in one socket.
- * cores: the number of cores in one cluster.
- * threads: the number of threads in one core.
- */
-typedef struct {
-	uint32_t sockets;
-	uint32_t clusters;
-	uint32_t cores;
-	uint32_t threads;
-} cpu_topology;
-
-static struct {
-	uint32_t num_cpus;
-	uint32_t num_memnodes;
-	cpu_data cpu[PLATFORM_CORE_COUNT];
-	cpu_topology cpu_topo;
-	memory_data memory[PLAT_MAX_MEM_NODES];
-} dynamic_platform_info;
-
-void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base);
 uintptr_t sbsa_get_gicd(void);
 uintptr_t sbsa_get_gicr(void);
 
 /*
- * QEMU provides us with minimal information about hardware platform using
- * minimalistic DeviceTree. This is not a Linux DeviceTree. It is not even
- * a firmware DeviceTree.
- *
- * It is information passed from QEMU to describe the information a hardware
- * platform would have other mechanisms to discover at runtime, that are
- * affected by the QEMU command line.
- *
- * Ultimately this device tree will be replaced by IPC calls to an emulated SCP.
- * And when we do that, we won't then have to rewrite Normal world firmware to
- * cope.
- */
-
-static void read_cpu_topology_from_dt(void *dtb)
-{
-	int node;
-
-	/*
-	 * QEMU gives us this DeviceTree node when we config:
-	 * -smp 16,sockets=2,clusters=2,cores=2,threads=2
-	 *
-	 * topology {
-	 *	threads = <0x02>;
-	 *	cores = <0x02>;
-	 *	clusters = <0x02>;
-	 *	sockets = <0x02>;
-	 * };
-	 */
-
-	node = fdt_path_offset(dtb, "/cpus/topology");
-	if (node > 0) {
-		dynamic_platform_info.cpu_topo.sockets =
-			fdt_read_uint32_default(dtb, node, "sockets", 0);
-		dynamic_platform_info.cpu_topo.clusters =
-			fdt_read_uint32_default(dtb, node, "clusters", 0);
-		dynamic_platform_info.cpu_topo.cores =
-			fdt_read_uint32_default(dtb, node, "cores", 0);
-		dynamic_platform_info.cpu_topo.threads =
-			fdt_read_uint32_default(dtb, node, "threads", 0);
-	}
-
-	INFO("Cpu topology: sockets: %d, clusters: %d, cores: %d, threads: %d\n",
-		dynamic_platform_info.cpu_topo.sockets,
-		dynamic_platform_info.cpu_topo.clusters,
-		dynamic_platform_info.cpu_topo.cores,
-		dynamic_platform_info.cpu_topo.threads);
-}
-
-void read_cpuinfo_from_dt(void *dtb)
-{
-	int node;
-	int prev;
-	int cpu = 0;
-	uintptr_t mpidr;
-
-	/*
-	 * QEMU gives us this DeviceTree node:
-	 * numa-node-id entries are only when NUMA config is used
-	 *
-	 *  cpus {
-	 *  	#size-cells = <0x00>;
-	 *  	#address-cells = <0x02>;
-	 *
-	 *  	cpu@0 {
-	 *  	        numa-node-id = <0x00>;
-	 *  		reg = <0x00 0x00>;
-	 *  	};
-	 *
-	 *  	cpu@1 {
-	 *  	        numa-node-id = <0x03>;
-	 *  		reg = <0x00 0x01>;
-	 *  	};
-	 *  };
-	 */
-	node = fdt_path_offset(dtb, "/cpus");
-	if (node < 0) {
-		ERROR("No information about cpus in DeviceTree.\n");
-		panic();
-	}
-
-	/*
-	 * QEMU numbers cpus from 0 and there can be /cpus/cpu-map present so we
-	 * cannot use fdt_first_subnode() here
-	 */
-	node = fdt_path_offset(dtb, "/cpus/cpu@0");
-
-	while (node > 0) {
-		if (fdt_getprop(dtb, node, "reg", NULL)) {
-			fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL);
-		} else {
-			ERROR("Incomplete information for cpu %d in DeviceTree.\n", cpu);
-			panic();
-		}
-
-		dynamic_platform_info.cpu[cpu].mpidr = mpidr;
-		dynamic_platform_info.cpu[cpu].nodeid =
-			fdt_read_uint32_default(dtb, node, "numa-node-id", 0);
-
-		INFO("CPU %d: node-id: %d, mpidr: %ld\n", cpu,
-				dynamic_platform_info.cpu[cpu].nodeid, mpidr);
-
-		cpu++;
-
-		prev = node;
-		node = fdt_next_subnode(dtb, prev);
-	}
-
-	dynamic_platform_info.num_cpus = cpu;
-	INFO("Found %d cpus\n", dynamic_platform_info.num_cpus);
-
-	read_cpu_topology_from_dt(dtb);
-}
-
-void read_meminfo_from_dt(void *dtb)
-{
-	const fdt32_t *prop;
-	const char *type;
-	int prev, node;
-	int len;
-	uint32_t memnode = 0;
-	uint32_t higher_value, lower_value;
-	uint64_t cur_base, cur_size;
-
-	/*
-	 * QEMU gives us this DeviceTree node:
-	 *
-	 *	memory@100c0000000 {
-	 *		numa-node-id = <0x01>;
-	 *		reg = <0x100 0xc0000000 0x00 0x40000000>;
-	 *		device_type = "memory";
-	 *	};
-	 *
-	 *	memory@10000000000 {
-	 *		numa-node-id = <0x00>;
-	 *		reg = <0x100 0x00 0x00 0xc0000000>;
-	 *		device_type = "memory";
-	 *	}
-	 */
-
-	for (prev = 0;; prev = node) {
-		node = fdt_next_node(dtb, prev, NULL);
-		if (node < 0) {
-			break;
-		}
-
-		type = fdt_getprop(dtb, node, "device_type", &len);
-		if (type && strncmp(type, "memory", len) == 0) {
-			dynamic_platform_info.memory[memnode].nodeid =
-				fdt_read_uint32_default(dtb, node, "numa-node-id", 0);
-
-			/*
-			 * Get the 'reg' property of this node and
-			 * assume two 8 bytes for base and size.
-			 */
-			prop = fdt_getprop(dtb, node, "reg", &len);
-			if (prop != 0 && len == (2 * sizeof(int64_t))) {
-				higher_value = fdt32_to_cpu(*prop);
-				lower_value = fdt32_to_cpu(*(prop + 1));
-				cur_base = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32);
-
-				higher_value = fdt32_to_cpu(*(prop + 2));
-				lower_value = fdt32_to_cpu(*(prop + 3));
-				cur_size = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32);
-
-				dynamic_platform_info.memory[memnode].addr_base = cur_base;
-				dynamic_platform_info.memory[memnode].addr_size = cur_size;
-
-				INFO("RAM %d: node-id: %d, address: 0x%lx - 0x%lx\n",
-					memnode,
-					dynamic_platform_info.memory[memnode].nodeid,
-					dynamic_platform_info.memory[memnode].addr_base,
-					dynamic_platform_info.memory[memnode].addr_base +
-					dynamic_platform_info.memory[memnode].addr_size - 1);
-			}
-
-			memnode++;
-		}
-	}
-
-	dynamic_platform_info.num_memnodes = memnode;
-}
-
-void read_platform_config_from_dt(void *dtb)
-{
-	int node;
-	const fdt64_t *data;
-	int err;
-	uintptr_t gicd_base;
-	uintptr_t gicr_base;
-
-	/*
-	 * QEMU gives us this DeviceTree node:
-	 *
-	 * intc {
-	 *	 reg = < 0x00 0x40060000 0x00 0x10000
-	 *		 0x00 0x40080000 0x00 0x4000000>;
-	 *       its {
-	 *               reg = <0x00 0x44081000 0x00 0x20000>;
-	 *       };
-	 * };
-	 */
-	node = fdt_path_offset(dtb, "/intc");
-	if (node < 0) {
-		return;
-	}
-
-	data = fdt_getprop(dtb, node, "reg", NULL);
-	if (data == NULL) {
-		return;
-	}
-
-	err = fdt_get_reg_props_by_index(dtb, node, 0, &gicd_base, NULL);
-	if (err < 0) {
-		ERROR("Failed to read GICD reg property of GIC node\n");
-		return;
-	}
-	INFO("GICD base = 0x%lx\n", gicd_base);
-
-	err = fdt_get_reg_props_by_index(dtb, node, 1, &gicr_base, NULL);
-	if (err < 0) {
-		ERROR("Failed to read GICR reg property of GIC node\n");
-		return;
-	}
-	INFO("GICR base = 0x%lx\n", gicr_base);
-
-	sbsa_set_gic_bases(gicd_base, gicr_base);
-
-	node = fdt_path_offset(dtb, "/intc/its");
-	if (node < 0) {
-		return;
-	}
-
-	err = fdt_get_reg_props_by_index(dtb, node, 0, &gic_its_addr, NULL);
-	if (err < 0) {
-		ERROR("Failed to read GICI reg property of GIC node\n");
-		return;
-	}
-	INFO("GICI base = 0x%lx\n", gic_its_addr);
-}
-
-void read_platform_version(void *dtb)
-{
-	int node;
-
-	node = fdt_path_offset(dtb, "/");
-	if (node >= 0) {
-		platform_version_major =
-			fdt_read_uint32_default(dtb, node, "machine-version-major", 0);
-		platform_version_minor =
-			fdt_read_uint32_default(dtb, node, "machine-version-minor", 0);
-	}
-}
-
-void sip_svc_init(void)
-{
-	/* Read DeviceTree data before MMU is enabled */
-
-	void *dtb = (void *)(uintptr_t)ARM_PRELOADED_DTB_BASE;
-	int err;
-
-	err = fdt_open_into(dtb, dtb, PLAT_QEMU_DT_MAX_SIZE);
-	if (err < 0) {
-		ERROR("Invalid Device Tree at %p: error %d\n", dtb, err);
-		return;
-	}
-
-	err = fdt_check_header(dtb);
-	if (err < 0) {
-		ERROR("Invalid DTB file passed\n");
-		return;
-	}
-
-	read_platform_version(dtb);
-	INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor);
-
-	read_platform_config_from_dt(dtb);
-	read_cpuinfo_from_dt(dtb);
-	read_meminfo_from_dt(dtb);
-}
-
-/*
  * This function is responsible for handling all SiP calls from the NS world
  */
 uintptr_t sbsa_sip_smc_handler(uint32_t smc_fid,
@@ -378,49 +58,56 @@
 	switch (smc_fid) {
 	case SIP_SVC_VERSION:
 		INFO("Platform version requested\n");
-		SMC_RET3(handle, NULL, platform_version_major, platform_version_minor);
+		SMC_RET3(handle, NULL, sbsa_platform_version_major(),
+			 sbsa_platform_version_minor());
 
 	case SIP_SVC_GET_GIC:
 		SMC_RET3(handle, NULL, sbsa_get_gicd(), sbsa_get_gicr());
 
 	case SIP_SVC_GET_GIC_ITS:
-		SMC_RET2(handle, NULL, gic_its_addr);
+		SMC_RET2(handle, NULL, sbsa_platform_gic_its_addr());
 
 	case SIP_SVC_GET_CPU_COUNT:
-		SMC_RET2(handle, NULL, dynamic_platform_info.num_cpus);
+		SMC_RET2(handle, NULL, sbsa_platform_num_cpus());
 
 	case SIP_SVC_GET_CPU_NODE:
 		index = x1;
 		if (index < PLATFORM_CORE_COUNT) {
-			SMC_RET3(handle, NULL,
-				dynamic_platform_info.cpu[index].nodeid,
-				dynamic_platform_info.cpu[index].mpidr);
+			struct platform_cpu_data data;
+
+			data = sbsa_platform_cpu_node(index);
+
+			SMC_RET3(handle, NULL, data.nodeid, data.mpidr);
 		} else {
 			SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
 		}
 
 	case SIP_SVC_GET_CPU_TOPOLOGY:
-		if (dynamic_platform_info.cpu_topo.cores > 0) {
-			SMC_RET5(handle, NULL,
-			dynamic_platform_info.cpu_topo.sockets,
-			dynamic_platform_info.cpu_topo.clusters,
-			dynamic_platform_info.cpu_topo.cores,
-			dynamic_platform_info.cpu_topo.threads);
+		struct platform_cpu_topology topology;
+
+		topology = sbsa_platform_cpu_topology();
+
+		if (topology.cores > 0) {
+			SMC_RET5(handle, NULL, topology.sockets,
+				 topology.clusters, topology.cores,
+				 topology.threads);
 		} else {
 			/* we do not know topology so we report SMC as unknown */
 			SMC_RET1(handle, SMC_UNK);
 		}
 
 	case SIP_SVC_GET_MEMORY_NODE_COUNT:
-		SMC_RET2(handle, NULL, dynamic_platform_info.num_memnodes);
+		SMC_RET2(handle, NULL, sbsa_platform_num_memnodes());
 
 	case SIP_SVC_GET_MEMORY_NODE:
 		index = x1;
 		if (index < PLAT_MAX_MEM_NODES) {
-			SMC_RET4(handle, NULL,
-				dynamic_platform_info.memory[index].nodeid,
-				dynamic_platform_info.memory[index].addr_base,
-				dynamic_platform_info.memory[index].addr_size);
+			struct platform_memory_data data;
+
+			data = sbsa_platform_memory_node(index);
+
+			SMC_RET4(handle, NULL, data.nodeid,
+				 data.addr_base, data.addr_size);
 		} else {
 			SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
 		}
diff --git a/plat/qemu/qemu_sbsa/trp/trp-qemu_sbsa.mk b/plat/qemu/qemu_sbsa/trp/trp-qemu_sbsa.mk
new file mode 100644
index 0000000..07ccac0
--- /dev/null
+++ b/plat/qemu/qemu_sbsa/trp/trp-qemu_sbsa.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2024-2025, Linaro Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/qemu/common/trp/trp-qemu-common.mk
+
diff --git a/plat/qti/common/src/qti_gic_v3.c b/plat/qti/common/src/qti_gic_v3.c
index f00267a..746c6f1 100644
--- a/plat/qti/common/src/qti_gic_v3.c
+++ b/plat/qti/common/src/qti_gic_v3.c
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
- * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2024, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2024, The Linux Foundation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -54,24 +54,36 @@
 		       INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
 #endif
+#ifdef QTISECLIB_INT_ID_A2_NOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_A2_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
 		       INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
+#endif
+#ifdef QTISECLIB_INT_ID_CONFIG_NOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_CONFIG_NOC_ERROR,
 		       GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
+#endif
+#ifdef QTISECLIB_INT_ID_DC_NOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_DC_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
 		       INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
+#endif
+#ifdef QTISECLIB_INT_ID_MEM_NOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_MEM_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
 		       INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
+#endif
+#ifdef QTISECLIB_INT_ID_SYSTEM_NOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_SYSTEM_NOC_ERROR,
 		       GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
+#endif
+#ifdef QTISECLIB_INT_ID_MMSS_NOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_MMSS_NOC_ERROR,
 		       GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
 		       GIC_INTR_CFG_EDGE),
+#endif
 #ifdef QTISECLIB_INT_ID_LPASS_AGNOC_ERROR
 	INTR_PROP_DESC(QTISECLIB_INT_ID_LPASS_AGNOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
 		       INTR_GROUP0,
diff --git a/plat/qti/qcs615/inc/platform_def.h b/plat/qti/qcs615/inc/platform_def.h
new file mode 100644
index 0000000..5b8ff7d
--- /dev/null
+++ b/plat/qti/qcs615/inc/platform_def.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, The Linux Foundation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+/* Enable the dynamic translation tables library. */
+#define PLAT_XLAT_TABLES_DYNAMIC 1
+
+#include <common_def.h>
+
+#include <qti_board_def.h>
+#include <qtiseclib_defs_plat.h>
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/*
+ * MPIDR_PRIMARY_CPU
+ * You just need to have the correct core_affinity_val i.e. [7:0]
+ * and cluster_affinity_val i.e. [15:8]
+ * the other bits will be ignored
+ */
+/*----------------------------------------------------------------------------*/
+#define MPIDR_PRIMARY_CPU  0x0000
+/*----------------------------------------------------------------------------*/
+
+#define QTI_PWR_LVL0    MPIDR_AFFLVL0
+#define QTI_PWR_LVL1    MPIDR_AFFLVL1
+#define QTI_PWR_LVL2    MPIDR_AFFLVL2
+#define QTI_PWR_LVL3    MPIDR_AFFLVL3
+
+/*
+ *  Macros for local power states encoded by State-ID field
+ *  within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define QTI_LOCAL_STATE_RUN   0
+/*
+ * Local power state for clock-gating. Valid only for CPU and not cluster power
+ * domains
+ */
+#define QTI_LOCAL_STATE_STB   1
+/*
+ * Local power state for retention. Valid for CPU and cluster power
+ * domains
+ */
+#define QTI_LOCAL_STATE_RET   2
+/*
+ * Local power state for OFF/power down. Valid for CPU, cluster, RSC and PDC
+ * power domains
+ */
+#define QTI_LOCAL_STATE_OFF   3
+/*
+ * Local power state for DEEPOFF/power rail down. Valid for CPU, cluster and RSC
+ * power domains
+ */
+#define QTI_LOCAL_STATE_DEEPOFF  4
+
+/*
+ * 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 QTI_LOCAL_STATE_RET
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE QTI_LOCAL_STATE_DEEPOFF
+
+/******************************************************************************
+ * Required platform porting definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+/*
+ * Platform specific page table and MMU setup constants.
+ */
+#define MAX_MMAP_REGIONS   (PLAT_QTI_MMAP_ENTRIES)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ull << 36)
+
+#define ARM_CACHE_WRITEBACK_SHIFT   6
+
+/*
+ * Some data must be 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.
+ */
+#define CACHE_WRITEBACK_GRANULE     (1 << ARM_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * One cache line needed for bakery locks on ARM platforms
+ */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE   (1 * CACHE_WRITEBACK_GRANULE)
+
+/*----------------------------------------------------------------------------*/
+/* PSCI power domain topology definitions */
+/*----------------------------------------------------------------------------*/
+/* One domain each to represent RSC and PDC level */
+#define PLAT_PDC_COUNT        1
+#define PLAT_RSC_COUNT        1
+
+/* There is one top-level FCM cluster */
+#define PLAT_CLUSTER_COUNT    1
+
+/* No. of cores in the FCM cluster */
+#define PLAT_CLUSTER0_CORE_COUNT 8
+
+#define PLATFORM_CORE_COUNT      (PLAT_CLUSTER0_CORE_COUNT)
+
+#define PLAT_NUM_PWR_DOMAINS     (PLAT_PDC_COUNT +\
+									PLAT_RSC_COUNT   +\
+									PLAT_CLUSTER_COUNT  +\
+									PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL      3
+
+/*****************************************************************************/
+/* Memory mapped Generic timer interfaces  */
+/*****************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/* GIC-600 constants */
+/*----------------------------------------------------------------------------*/
+#define BASE_GICD_BASE     0x17A00000
+#define BASE_GICR_BASE     0x17A60000
+#define BASE_GICC_BASE     0x0
+#define BASE_GICH_BASE     0x0
+#define BASE_GICV_BASE     0x0
+
+#define QTI_GICD_BASE      BASE_GICD_BASE
+#define QTI_GICR_BASE      BASE_GICR_BASE
+#define QTI_GICC_BASE      BASE_GICC_BASE
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+/* UART related constants. */
+/*----------------------------------------------------------------------------*/
+/* BASE ADDRESS OF DIFFERENT REGISTER SPACES IN HW */
+#define GENI4_CFG          0x0
+#define GENI4_IMAGE_REGS   0x100
+#define GENI4_DATA         0x600
+
+/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */
+#define GENI_STATUS_REG                      (GENI4_CFG + 0x00000040)
+#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK   (0x1)
+#define UART_TX_TRANS_LEN_REG                (GENI4_IMAGE_REGS + 0x00000170)
+/* MASTER/TX ENGINE REGISTERS */
+#define GENI_M_CMD0_REG                      (GENI4_DATA + 0x00000000)
+/* FIFO, STATUS REGISTERS AND MASKS */
+#define GENI_TX_FIFOn_REG                    (GENI4_DATA + 0x00000100)
+
+#define GENI_M_CMD_TX                        (0x08000000)
+
+/*----------------------------------------------------------------------------*/
+/* Device address space for mapping. Excluding starting 4K */
+/*----------------------------------------------------------------------------*/
+#define QTI_DEVICE_BASE          0x1000
+#define QTI_DEVICE_SIZE          (0x80000000 - QTI_DEVICE_BASE)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at DDR as per memory map. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define BL31_LIMIT            (BL31_BASE + BL31_SIZE)
+
+/*----------------------------------------------------------------------------*/
+/* AOSS registers */
+/*----------------------------------------------------------------------------*/
+#define QTI_PS_HOLD_REG             0x0C264000
+/*----------------------------------------------------------------------------*/
+/* AOP CMD DB  address space for mapping */
+/*----------------------------------------------------------------------------*/
+#define QTI_AOP_CMD_DB_BASE         0x85F20000
+#define QTI_AOP_CMD_DB_SIZE         0x00020000
+/*----------------------------------------------------------------------------*/
+/* SOC hw version register */
+/*----------------------------------------------------------------------------*/
+#define QTI_SOC_VERSION_MASK        U(0xFFFF)
+#define QTI_SOC_REVISION_REG        0x1FC8000
+#define QTI_SOC_REVISION_MASK       U(0xFFFF)
+/*----------------------------------------------------------------------------*/
+/* LC PON register offsets */
+/*----------------------------------------------------------------------------*/
+#define PON_PS_HOLD_RESET_CTL       0x85a
+#define PON_PS_HOLD_RESET_CTL2      0x85b
+/*----------------------------------------------------------------------------*/
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qti/qcs615/inc/qti_map_chipinfo.h b/plat/qti/qcs615/inc/qti_map_chipinfo.h
new file mode 100644
index 0000000..6092ea0
--- /dev/null
+++ b/plat/qti/qcs615/inc/qti_map_chipinfo.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2024, The Linux Foundation. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef QTI_MAP_CHIPINFO_H
+#define QTI_MAP_CHIPINFO_H
+
+#include <stdint.h>
+
+#include <qti_plat.h>
+
+#define QTI_JTAG_ID_REG                         0x786130
+#define QTI_JTAG_ID_SHIFT                       12
+#define QTI_JTAG_ID_QCS615                      U(0x02E9)
+#define QTI_JTAG_ID_SA6155P                     U(0x00EE)
+#define QTI_CHIPINFO_ID_QCS615                  U(0x01E7)
+#define QTI_CHIPINFO_ID_SA6155P                 U(0x0179)
+#define QTI_DEFAULT_CHIPINFO_ID                 U(0xFFFF)
+
+static const chip_id_info_t g_map_jtag_chipinfo_id[] = {
+	{QTI_JTAG_ID_QCS615,  QTI_CHIPINFO_ID_QCS615},
+	{QTI_JTAG_ID_SA6155P, QTI_CHIPINFO_ID_SA6155P},
+};
+
+#endif /* QTI_MAP_CHIPINFO_H */
diff --git a/plat/qti/qcs615/inc/qti_rng_io.h b/plat/qti/qcs615/inc/qti_rng_io.h
new file mode 100644
index 0000000..b5e521e
--- /dev/null
+++ b/plat/qti/qcs615/inc/qti_rng_io.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2024, The Linux Foundation. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef QTI_RNG_IO_H
+#define QTI_RNG_IO_H
+
+#define SEC_PRNG_STATUS			            0x791004
+#define SEC_PRNG_STATUS_DATA_AVAIL_BMSK	0x1
+#define SEC_PRNG_DATA_OUT		            0x791000
+
+#endif /* QTI_RNG_IO_H */
+
diff --git a/plat/qti/qcs615/inc/qti_secure_io_cfg.h b/plat/qti/qcs615/inc/qti_secure_io_cfg.h
new file mode 100644
index 0000000..a78583e
--- /dev/null
+++ b/plat/qti/qcs615/inc/qti_secure_io_cfg.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2024, The Linux Foundation. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QTI_SECURE_IO_CFG_H
+#define QTI_SECURE_IO_CFG_H
+
+#include <stdint.h>
+
+/*
+ * List of peripheral/IO memory areas that are protected from
+ * non-secure world but not required to be secure.
+ */
+#define APPS_SMMU_TBU_PWR_STATUS             0x15002204
+#define APPS_SMMU_CUSTOM_CFG                 0x15002300
+#define APPS_SMMU_STATS_SYNC_INV_TBU_ACK     0x150025DC
+#define APPS_SMMU_SAFE_SEC_CFG               0x15002644
+#define APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x15002648
+
+static const uintptr_t qti_secure_io_allowed_regs[] = {
+	APPS_SMMU_TBU_PWR_STATUS,
+	APPS_SMMU_CUSTOM_CFG,
+	APPS_SMMU_STATS_SYNC_INV_TBU_ACK,
+	APPS_SMMU_SAFE_SEC_CFG,
+	APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
+};
+
+static const uintptr_t qti_secure_io_debug_allowed_regs[] = {
+};
+
+
+#endif /* QTI_SECURE_IO_CFG_H */
diff --git a/plat/qti/qcs615/platform.mk b/plat/qti/qcs615/platform.mk
new file mode 100644
index 0000000..a3136cb
--- /dev/null
+++ b/plat/qti/qcs615/platform.mk
@@ -0,0 +1,142 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2024, The Linux Foundation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Makefile for QCS615 QTI platform.
+
+QTI_PLAT_PATH	:=	plat/qti
+CHIPSET			:=	${PLAT}
+
+# Turn On Separate code & data.
+SEPARATE_CODE_AND_RODATA		:=	1
+USE_COHERENT_MEM					:=	0
+WARMBOOT_ENABLE_DCACHE_EARLY	:=	1
+HW_ASSISTED_COHERENCY			:=	1
+
+# Enable errata configs for cortex_a76 and cortex_a55
+# QCS615 CPU core revisions are r1p0
+ERRATA_A55_1221012				:=	1
+ERRATA_A55_1530923				:=	1
+ERRATA_A76_1073348				:=	1
+ERRATA_A76_1130799				:=	1
+ERRATA_A76_1220197				:=	1
+ERRATA_A76_1257314				:=	1
+ERRATA_A76_1262606				:=	1
+ERRATA_A76_1262888				:=	1
+ERRATA_A76_1275112				:=	1
+ERRATA_A76_1791580				:=	1
+ERRATA_A76_1165522				:=	1
+ERRATA_A76_1868343				:=	1
+ERRATA_A76_1946160				:=	1
+ERRATA_A76_2743102				:=	1
+
+# Disable the PSCI platform compatibility layer
+ENABLE_PLAT_COMPAT				:=	0
+
+# Enable PSCI v1.0 extended state ID format
+PSCI_EXTENDED_STATE_ID			:=	1
+ARM_RECOM_STATE_ID_ENC			:=	1
+PSCI_OS_INIT_MODE					:=	1
+
+COLD_BOOT_SINGLE_CPU				:=	1
+PROGRAMMABLE_RESET_ADDRESS		:=	1
+
+RESET_TO_BL31						:=	0
+
+QTI_SDI_BUILD						:=	0
+$(eval $(call assert_boolean,QTI_SDI_BUILD))
+$(eval $(call add_define,QTI_SDI_BUILD))
+
+#disable CTX_INCLUDE_AARCH32_REGS to support QCS615 gold cores
+override CTX_INCLUDE_AARCH32_REGS	:=	0
+
+# Set dynamic CVE_2018_3639 explicitly as it defaults to 0.
+# Others which are applicable: CVE_2017_5715 & CVE_2022_23960 default to 1
+DYNAMIC_WORKAROUND_CVE_2018_3639	:=	1
+
+# Enable stack protector.
+ENABLE_STACK_PROTECTOR				:=	strong
+
+
+QTI_EXTERNAL_INCLUDES	:=	-I${QTI_PLAT_PATH}/${CHIPSET}/inc			\
+				-I${QTI_PLAT_PATH}/common/inc				\
+				-I${QTI_PLAT_PATH}/common/inc/$(ARCH)			\
+				-I${QTI_PLAT_PATH}/qtiseclib/inc			\
+				-I${QTI_PLAT_PATH}/qtiseclib/inc/${CHIPSET}			\
+
+QTI_BL31_SOURCES	:=	$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_helpers.S	\
+				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_silver.S	\
+				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_gold.S	\
+				$(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S	\
+				$(QTI_PLAT_PATH)/common/src/pm_ps_hold.c			\
+				$(QTI_PLAT_PATH)/common/src/qti_stack_protector.c	\
+				$(QTI_PLAT_PATH)/common/src/qti_common.c		\
+				$(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c		\
+				$(QTI_PLAT_PATH)/common/src/qti_gic_v3.c		\
+				$(QTI_PLAT_PATH)/common/src/qti_interrupt_svc.c		\
+				$(QTI_PLAT_PATH)/common/src/qti_syscall.c		\
+				$(QTI_PLAT_PATH)/common/src/qti_topology.c		\
+				$(QTI_PLAT_PATH)/common/src/qti_pm.c			\
+				$(QTI_PLAT_PATH)/common/src/qti_rng.c			\
+				$(QTI_PLAT_PATH)/common/src/spmi_arb.c			\
+				$(QTI_PLAT_PATH)/qtiseclib/src/qtiseclib_cb_interface.c	\
+
+
+PLAT_INCLUDES		:=	-Iinclude/plat/common/					\
+						${QTI_EXTERNAL_INCLUDES}
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}						\
+							plat/common/aarch64/crash_console_helpers.S	\
+							common/desc_image_load.c					\
+							lib/bl_aux_params/bl_aux_params.c			\
+
+include lib/coreboot/coreboot.mk
+
+#PSCI Sources.
+PSCI_SOURCES		:=	plat/common/plat_psci_common.c				\
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600	:=	1
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+#Timer sources
+TIMER_SOURCES		:=	drivers/delay_timer/generic_delay_timer.c	\
+						drivers/delay_timer/delay_timer.c		\
+
+#GIC sources.
+GIC_SOURCES		:=	plat/common/plat_gicv3.c			\
+					${GICV3_SOURCES}				\
+
+CPU_SOURCES		:=	lib/cpus/aarch64/cortex_a76.S			\
+					lib/cpus/aarch64/cortex_a55.S			\
+
+BL31_SOURCES		+=	${QTI_BL31_SOURCES}				\
+				${PSCI_SOURCES}					\
+				${GIC_SOURCES}					\
+				${TIMER_SOURCES}				\
+				${CPU_SOURCES}					\
+
+LIB_QTI_PATH	:=	${QTI_PLAT_PATH}/qtiseclib/lib/${CHIPSET}
+
+
+# Override this on the command line to point to the qtiseclib library which
+# will be available in coreboot.org
+QTISECLIB_PATH ?=
+
+ifeq ($(QTISECLIB_PATH),)
+# if No lib then use stub implementation for qtiseclib interface
+$(warning QTISECLIB_PATH is not provided while building, using stub implementation. \
+		Please refer docs/plat/qti.rst for more details \
+		THIS FIRMWARE WILL NOT BOOT!)
+BL31_SOURCES	+=	plat/qti/qtiseclib/src/qtiseclib_interface_stub.c
+else
+# use library provided by QTISECLIB_PATH
+LDFLAGS += -L $(dir $(QTISECLIB_PATH))
+LDLIBS += -l$(patsubst lib%.a,%,$(notdir $(QTISECLIB_PATH)))
+endif
+
diff --git a/plat/qti/qtiseclib/inc/qcs615/qtiseclib_defs_plat.h b/plat/qti/qtiseclib/inc/qcs615/qtiseclib_defs_plat.h
new file mode 100644
index 0000000..2dbcc83
--- /dev/null
+++ b/plat/qti/qtiseclib/inc/qcs615/qtiseclib_defs_plat.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2024, The Linux Foundation. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __QTISECLIB_DEFS_PLAT_H__
+#define __QTISECLIB_DEFS_PLAT_H__
+
+#define QTISECLIB_PLAT_CLUSTER_COUNT   1
+#define QTISECLIB_PLAT_CORE_COUNT      8
+
+#define BL31_BASE                0x86200000
+#define BL31_SIZE                0x00100000
+
+/*----------------------------------------------------------------------------*/
+/* AOP CMD DB  address space for mapping */
+/*----------------------------------------------------------------------------*/
+#define QTI_AOP_CMD_DB_BASE         0x85F20000
+#define QTI_AOP_CMD_DB_SIZE         0x00020000
+
+/* Chipset specific secure interrupt number/ID defs. */
+#define QTISECLIB_INT_ID_SEC_WDOG_BARK          (0x204)
+#define QTISECLIB_INT_ID_NON_SEC_WDOG_BITE      (0x21)
+
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC     (0xE6)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC  (0xE7)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC     (0xE8)
+#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC  (0xE9)
+
+#define QTISECLIB_INT_ID_XPU_SEC                (0xE3)
+#define QTISECLIB_INT_ID_XPU_NON_SEC            (0xE4)
+
+//NOC INterrupt
+#define QTISECLIB_INT_ID_A1_NOC_ERROR        (0x18B)
+#define QTISECLIB_INT_ID_CONFIG_NOC_ERROR    (0xE2)
+#define QTISECLIB_INT_ID_DC_NOC_ERROR        (0x122)
+#define QTISECLIB_INT_ID_MEM_NOC_ERROR       (0x6C) //GEM_NOC
+#define QTISECLIB_INT_ID_SYSTEM_NOC_ERROR    (0xC6)
+#define QTISECLIB_INT_ID_MMSS_NOC_ERROR      (0xBA)
+
+#endif /* __QTISECLIB_DEFS_PLAT_H__ */
diff --git a/plat/rockchip/common/drivers/pmu/pmu_com.h b/plat/rockchip/common/drivers/pmu/pmu_com.h
index 022bb02..84f9421 100644
--- a/plat/rockchip/common/drivers/pmu/pmu_com.h
+++ b/plat/rockchip/common/drivers/pmu/pmu_com.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -32,8 +32,6 @@
 };
 
 #pragma weak plat_ic_get_pending_interrupt_id
-#pragma weak pmu_power_domain_ctr
-#pragma weak check_cpu_wfie
 
 static inline uint32_t pmu_power_domain_st(uint32_t pd)
 {
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.c b/plat/rockchip/px30/drivers/pmu/pmu.c
index 8770b2e..0d8e8b6 100644
--- a/plat/rockchip/px30/drivers/pmu/pmu.c
+++ b/plat/rockchip/px30/drivers/pmu/pmu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -867,18 +867,6 @@
 		ERROR("Can't wait pll:%d lock\n", pll_id);
 }
 
-static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd)
-{
-	mmio_write_32(pll_base + PLL_CON(1),
-		      BITS_WITH_WMASK(1, 1U, 15));
-	if (pd)
-		mmio_write_32(pll_base + PLL_CON(1),
-			      BITS_WITH_WMASK(1, 1, 14));
-	else
-		mmio_write_32(pll_base + PLL_CON(1),
-			      BITS_WITH_WMASK(0, 1, 14));
-}
-
 static inline void pll_set_mode(uint32_t pll_id, uint32_t mode)
 {
 	uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id));
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.c b/plat/rockchip/rk3288/drivers/pmu/pmu.c
index 085976c..9e17cff 100644
--- a/plat/rockchip/rk3288/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -36,90 +36,6 @@
 	ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1,
 };
 
-static inline int rk3288_pmu_bus_idle(uint32_t req, uint32_t idle)
-{
-	uint32_t mask = BIT(req);
-	uint32_t idle_mask = 0;
-	uint32_t idle_target = 0;
-	uint32_t val;
-	uint32_t wait_cnt = 0;
-
-	switch (req) {
-	case bus_ide_req_gpu:
-		idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu);
-		idle_target = (idle << pmu_idle_ack_gpu) |
-			      (idle << pmu_idle_gpu);
-		break;
-	case bus_ide_req_core:
-		idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core);
-		idle_target = (idle << pmu_idle_ack_core) |
-			      (idle << pmu_idle_core);
-		break;
-	case bus_ide_req_cpup:
-		idle_mask = BIT(pmu_idle_ack_cpup) | BIT(pmu_idle_cpup);
-		idle_target = (idle << pmu_idle_ack_cpup) |
-			      (idle << pmu_idle_cpup);
-		break;
-	case bus_ide_req_bus:
-		idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus);
-		idle_target = (idle << pmu_idle_ack_bus) |
-			      (idle << pmu_idle_bus);
-		break;
-	case bus_ide_req_dma:
-		idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma);
-		idle_target = (idle << pmu_idle_ack_dma) |
-			      (idle << pmu_idle_dma);
-		break;
-	case bus_ide_req_peri:
-		idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri);
-		idle_target = (idle << pmu_idle_ack_peri) |
-			      (idle << pmu_idle_peri);
-		break;
-	case bus_ide_req_video:
-		idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video);
-		idle_target = (idle << pmu_idle_ack_video) |
-			      (idle << pmu_idle_video);
-		break;
-	case bus_ide_req_hevc:
-		idle_mask = BIT(pmu_idle_ack_hevc) | BIT(pmu_idle_hevc);
-		idle_target = (idle << pmu_idle_ack_hevc) |
-			      (idle << pmu_idle_hevc);
-		break;
-	case bus_ide_req_vio:
-		idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio);
-		idle_target = (pmu_idle_ack_vio) |
-			      (idle << pmu_idle_vio);
-		break;
-	case bus_ide_req_alive:
-		idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive);
-		idle_target = (idle << pmu_idle_ack_alive) |
-			      (idle << pmu_idle_alive);
-		break;
-	default:
-		ERROR("%s: Unsupported the idle request\n", __func__);
-		break;
-	}
-
-	val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ);
-	if (idle)
-		val |= mask;
-	else
-		val &= ~mask;
-
-	mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val);
-
-	while ((mmio_read_32(PMU_BASE +
-	       PMU_BUS_IDE_ST) & idle_mask) != idle_target) {
-		wait_cnt++;
-		if (!(wait_cnt % MAX_WAIT_CONUT))
-			WARN("%s:st=%x(%x)\n", __func__,
-			     mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST),
-			     idle_mask);
-	}
-
-	return 0;
-}
-
 static bool rk3288_sleep_disable_osc(void)
 {
 	static const uint32_t reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0,
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
index 3cdb7a2..49faba8 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -778,7 +778,7 @@
 	else if (twr_tmp <= 8)
 		twr_tmp = 8;
 	else if (twr_tmp <= 12)
-		twr_tmp = twr_tmp;
+		; /* do nothing */
 	else if (twr_tmp <= 14)
 		twr_tmp = 14;
 	else
diff --git a/plat/rockchip/rk3399/drivers/m0/Makefile b/plat/rockchip/rk3399/drivers/m0/Makefile
index 7913190..2bc87ae 100644
--- a/plat/rockchip/rk3399/drivers/m0/Makefile
+++ b/plat/rockchip/rk3399/drivers/m0/Makefile
@@ -5,13 +5,11 @@
 #
 
 include ../../../../../make_helpers/common.mk
+include ../../../../../make_helpers/build_macros.mk
 include ../../../../../make_helpers/toolchain.mk
 
-# Cross Compile
-M0_CROSS_COMPILE ?= arm-none-eabi-
-
 # Build architecture
-ARCH		:= cortex-m0
+ARCH		:= rk3399-m0
 
 # Build platform
 PLAT_M0		?= rk3399m0
@@ -27,10 +25,13 @@
 C_SOURCES_PMU		:= src/suspend.c
 
 # Flags definition
-COMMON_FLAGS		:= -g -mcpu=$(ARCH) -mthumb -Wall -O3 -nostdlib -mfloat-abi=soft
+COMMON_FLAGS		:= -g -mcpu=cortex-m0 -mthumb -Wall -O3 -nostdlib -mfloat-abi=soft
 CFLAGS			:= -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-common
-ASFLAGS			:= -Wa,--gdwarf-2
-LDFLAGS			:= -Wl,--gc-sections -Wl,--build-id=none
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105523
+CFLAGS			+= $(call cc_option, --param=min-pagesize=0)
+ASFLAGS			:= -Wa,--gdwarf-2 -Wa,--fatal-warnings
+LDFLAGS			:= -Wl,--gc-sections -Wl,--build-id=none -Wl,--fatal-warnings -z noexecstack
+LDFLAGS			+= $(call ld_option,-Xlinker --no-warn-rwx-segments)
 
 # NOTE: The line continuation '\' is required in the next define otherwise we
 # end up with a line-feed characer at the end of the last c filename.
@@ -62,7 +63,7 @@
 
 $(OBJ) : $(2)
 	$(s)echo "  CC      $$<"
-	$$(q)$(rk3399-m0-cc) $$(COMMON_FLAGS) $$(CFLAGS) $$(INCLUDES) -MMD -MT $$@ -c $$< -o $$@
+	$$(q)$($(ARCH)-cc) $$(COMMON_FLAGS) $$(CFLAGS) $$(INCLUDES) -MMD -MT $$@ -c $$< -o $$@
 endef
 
 define MAKE_S
@@ -70,7 +71,7 @@
 
 $(OBJ) : $(2)
 	$(s)echo "  AS      $$<"
-	$$(q)$(rk3399-m0-cc) -x assembler-with-cpp $$(COMMON_FLAGS) $$(ASFLAGS) -c $$< -o $$@
+	$$(q)$($(ARCH)-as) -x assembler-with-cpp $$(COMMON_FLAGS) $$(ASFLAGS) -c $$< -o $$@
 endef
 
 define MAKE_OBJS
@@ -91,20 +92,20 @@
 .DEFAULT_GOAL := all
 
 $(LINKERFILE): $(LINKERFILE_SRC)
-	$(rk3399-m0-cc) $(COMMON_FLAGS) $(INCLUDES) -P -E -D__LINKER__ -MMD -MF $@.d -MT $@ -o $@ $<
+	$(q)$($(ARCH)-cc) $(COMMON_FLAGS) $(INCLUDES) -P -E -D__LINKER__ -MMD -MF $@.d -MT $@ -o $@ $<
 -include $(LINKERFILE).d
 
 $(ELF) : $(OBJS) $(OBJS_COMMON) $(LINKERFILE)
 	$(s)echo "  LD      $@"
-	$(q)$(rk3399-m0-cc) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS) $(OBJS_COMMON)
+	$(q)$($(ARCH)-ld) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS) $(OBJS_COMMON)
 
 %.bin : %.elf
 	$(s)echo "  BIN     $@"
-	$(q)$(rk3399-m0-oc) -O binary $< $@
+	$(q)$($(ARCH)-oc) -O binary $< $@
 
 $(ELF_PMU) : $(OBJS_COMMON) $(OBJS_PMU) $(LINKERFILE)
 	$(s)echo "  LD      $@"
-	$(q)$(rk3399-m0-cc) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE_PMU) -Wl,-T$(LINKERFILE) $(OBJS_PMU) $(OBJS_COMMON)
+	$(q)$($(ARCH)-ld) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE_PMU) -Wl,-T$(LINKERFILE) $(OBJS_PMU) $(OBJS_COMMON)
 
 $(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_COMMON),$(1)))
 $(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES),$(1)))
diff --git a/plat/rockchip/rk3588/drivers/pmu/pmu.c b/plat/rockchip/rk3588/drivers/pmu/pmu.c
index f693dbd..a4128b2 100644
--- a/plat/rockchip/rk3588/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3588/drivers/pmu/pmu.c
@@ -760,10 +760,10 @@
 			  "mrs	x0, S3_0_C15_C2_7\n"
 			  "orr	x0, x0, #0x1\n"
 			  "msr	S3_0_C15_C2_7, x0\n"
-			  "wfi_loop:\n"
+			  "1:\n"
 			  "isb\n"
 			  "wfi\n"
-			  "b wfi_loop\n");
+			  "b 1b\n");
 }
 
 static void nonboot_cpus_off(void)
diff --git a/plat/st/common/include/stm32mp_svc_setup.h b/plat/st/common/include/stm32mp_svc_setup.h
new file mode 100644
index 0000000..e0e0d7f
--- /dev/null
+++ b/plat/st/common/include/stm32mp_svc_setup.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_SVC_SETUP_H
+#define STM32MP_SVC_SETUP_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/* Common SMC function IDs for STM32 Service queries across STM32MP paltforms */
+#define STM32_SIP_SVC_CALL_COUNT	0x8200ff00
+#define STM32_SIP_SVC_UID		0x8200ff01
+/*					0x8200ff02 is reserved */
+#define STM32_SIP_SVC_VERSION		0x8200ff03
+
+/* STM32 SiP Service Calls version numbers */
+#define STM32_SIP_SVC_VERSION_MAJOR	0x0
+#define STM32_SIP_SVC_VERSION_MINOR	0x1
+
+/* SMC error codes */
+#define STM32_SMC_OK			0x00000000U
+#define STM32_SMC_NOT_SUPPORTED		0xFFFFFFFFU
+#define STM32_SMC_FAILED		0xFFFFFFFEU
+#define STM32_SMC_INVALID_PARAMS	0xFFFFFFFDU
+
+void plat_svc_smc_handler(uint32_t smc_fid, u_register_t x1,
+			  u_register_t x2, u_register_t x3,
+			  u_register_t x4, uint32_t *ret1,
+			  uint32_t *ret2, bool *ret2_enabled,
+			  u_register_t flags);
+
+#endif /* STM32MP_SVC_SETUP_H */
diff --git a/plat/st/common/stm32mp_svc_setup.c b/plat/st/common/stm32mp_svc_setup.c
new file mode 100644
index 0000000..7fce896
--- /dev/null
+++ b/plat/st/common/stm32mp_svc_setup.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014-2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/scmi-msg.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+#include <tools_share/uuid.h>
+
+#include <stm32mp_svc_setup.h>
+
+/* STM32 SiP Service UUID */
+DEFINE_SVC_UUID2(stm32_sip_svc_uid,
+		 0xa778aa50, 0xf49b, 0x144a, 0x8a, 0x5e,
+		 0x26, 0x4d, 0x59, 0x94, 0xc2, 0x14);
+
+/* Setup STM32MP Standard Services */
+static int32_t stm32mp_svc_setup(void)
+{
+	/*
+	 * PSCI is the only specification implemented as a Standard Service.
+	 * Invoke PSCI setup from here.
+	 */
+	return 0;
+}
+
+/*
+ * Top-level Standard Service SMC handler. This handler will dispatch the SMC
+ * to the correct feature handler or default call a platform handler
+ */
+static uintptr_t stm32mp_svc_smc_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)
+{
+	uint32_t ret1 = 0U, ret2 = 0U;
+	bool ret_uid = false, ret2_enabled = false;
+
+	switch (smc_fid) {
+	case STM32_SIP_SVC_UID:
+		/* Return UUID to the caller */
+		ret_uid = true;
+		break;
+
+	case STM32_SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		ret1 = STM32_SIP_SVC_VERSION_MAJOR;
+		ret2 = STM32_SIP_SVC_VERSION_MINOR;
+		ret2_enabled = true;
+		break;
+	default:
+		plat_svc_smc_handler(smc_fid, x1, x2, x3, x4, &ret1, &ret2, &ret2_enabled, flags);
+		break;
+	}
+
+	if (ret_uid) {
+		SMC_UUID_RET(handle, stm32_sip_svc_uid);
+	}
+
+	if (ret2_enabled) {
+		SMC_RET2(handle, ret1, ret2);
+	}
+
+	SMC_RET1(handle, ret1);
+}
+
+/* Register Standard Service Calls as runtime service */
+DECLARE_RT_SVC(stm32mp_sip_svc,
+	       OEN_SIP_START,
+	       OEN_SIP_END,
+	       SMC_TYPE_FAST,
+	       stm32mp_svc_setup,
+	       stm32mp_svc_smc_handler
+);
diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h
index 52088de..ca4c88d 100644
--- a/plat/st/stm32mp1/include/stm32mp1_smc.h
+++ b/plat/st/stm32mp1/include/stm32mp1_smc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2024, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -39,16 +39,6 @@
 #define STM32_SIP_SMC_SCMI_AGENT0	0x82002000
 #define STM32_SIP_SMC_SCMI_AGENT1	0x82002001
 
-/* SMC function IDs for SiP Service queries */
-#define STM32_SIP_SVC_CALL_COUNT	0x8200ff00
-#define STM32_SIP_SVC_UID		0x8200ff01
-/*					0x8200ff02 is reserved */
-#define STM32_SIP_SVC_VERSION		0x8200ff03
-
-/* STM32 SiP Service Calls version numbers */
-#define STM32_SIP_SVC_VERSION_MAJOR	0x0
-#define STM32_SIP_SVC_VERSION_MINOR	0x1
-
 /* Number of STM32 SiP Calls implemented */
 #define STM32_COMMON_SIP_NUM_CALLS	3
 
@@ -58,10 +48,4 @@
 #define STM32_SMC_WRITE_SHADOW		0x03
 #define STM32_SMC_READ_OTP		0x04
 
-/* SMC error codes */
-#define STM32_SMC_OK			0x00000000U
-#define STM32_SMC_NOT_SUPPORTED		0xFFFFFFFFU
-#define STM32_SMC_FAILED		0xFFFFFFFEU
-#define STM32_SMC_INVALID_PARAMS	0xFFFFFFFDU
-
 #endif /* STM32MP1_SMC_H */
diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c
index 7cc0013..418a2e5 100644
--- a/plat/st/stm32mp1/services/bsec_svc.c
+++ b/plat/st/stm32mp1/services/bsec_svc.c
@@ -11,6 +11,7 @@
 
 #include <platform_def.h>
 #include <stm32mp1_smc.h>
+#include <stm32mp_svc_setup.h>
 
 #include "bsec_svc.h"
 
diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
index ed8a448..6e5544d 100644
--- a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
+++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2014-2024, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,56 +14,27 @@
 #include <tools_share/uuid.h>
 
 #include <stm32mp1_smc.h>
+#include <stm32mp_svc_setup.h>
 
 #include "bsec_svc.h"
 
-/* STM32 SiP Service UUID */
-DEFINE_SVC_UUID2(stm32_sip_svc_uid,
-		 0xa778aa50, 0xf49b, 0x144a, 0x8a, 0x5e,
-		 0x26, 0x4d, 0x59, 0x94, 0xc2, 0x14);
-
-/* Setup STM32MP1 Standard Services */
-static int32_t stm32mp1_svc_setup(void)
-{
-	/*
-	 * PSCI is the only specification implemented as a Standard Service.
-	 * Invoke PSCI setup from here.
-	 */
-	return 0;
-}
-
 /*
- * Top-level Standard Service SMC handler. This handler will in turn dispatch
- * calls to PSCI SMC handler.
+ * Platform Standard Service SMC handler. This handler will dispatch
+ * calls to features handlers.
  */
-static uintptr_t stm32mp1_svc_smc_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)
+void plat_svc_smc_handler(uint32_t smc_fid, u_register_t x1,
+			  u_register_t x2, u_register_t x3,
+			  u_register_t x4, uint32_t *ret1,
+			  uint32_t *ret2, bool *ret2_enabled,
+			  u_register_t flags)
 {
-	uint32_t ret1 = 0U, ret2 = 0U;
-	bool ret_uid = false, ret2_enabled = false;
-
 	switch (smc_fid) {
 	case STM32_SIP_SVC_CALL_COUNT:
-		ret1 = STM32_COMMON_SIP_NUM_CALLS;
-		break;
-
-	case STM32_SIP_SVC_UID:
-		/* Return UUID to the caller */
-		ret_uid = true;
-		break;
-
-	case STM32_SIP_SVC_VERSION:
-		/* Return the version of current implementation */
-		ret1 = STM32_SIP_SVC_VERSION_MAJOR;
-		ret2 = STM32_SIP_SVC_VERSION_MINOR;
-		ret2_enabled = true;
+		*ret1 = STM32_COMMON_SIP_NUM_CALLS;
 		break;
-
 	case STM32_SMC_BSEC:
-		ret1 = bsec_main(x1, x2, x3, &ret2);
-		ret2_enabled = true;
+		*ret1 = bsec_main(x1, x2, x3, ret2);
+		*ret2_enabled = true;
 		break;
 
 	case STM32_SIP_SMC_SCMI_AGENT0:
@@ -75,26 +46,7 @@
 
 	default:
 		WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid);
-		ret1 = STM32_SMC_NOT_SUPPORTED;
+		*ret1 = STM32_SMC_NOT_SUPPORTED;
 		break;
 	}
-
-	if (ret_uid) {
-		SMC_UUID_RET(handle, stm32_sip_svc_uid);
-	}
-
-	if (ret2_enabled) {
-		SMC_RET2(handle, ret1, ret2);
-	}
-
-	SMC_RET1(handle, ret1);
 }
-
-/* Register Standard Service Calls as runtime service */
-DECLARE_RT_SVC(stm32mp1_sip_svc,
-	       OEN_SIP_START,
-	       OEN_SIP_END,
-	       SMC_TYPE_FAST,
-	       stm32mp1_svc_setup,
-	       stm32mp1_svc_smc_handler
-);
diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
index 9695c9b..0e34848 100644
--- a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
+++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
@@ -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
 #
@@ -45,6 +45,7 @@
 				drivers/scmi-msg/smt.c
 
 # stm32mp1 specific services
-BL32_SOURCES		+=	plat/st/stm32mp1/services/bsec_svc.c		\
+BL32_SOURCES		+=	plat/st/common/stm32mp_svc_setup.c		\
+				plat/st/stm32mp1/services/bsec_svc.c		\
 				plat/st/stm32mp1/services/stm32mp1_svc_setup.c	\
 				plat/st/stm32mp1/stm32mp1_scmi.c
diff --git a/plat/st/stm32mp2/bl2_plat_setup.c b/plat/st/stm32mp2/bl2_plat_setup.c
index 2fabc41..621b784 100644
--- a/plat/st/stm32mp2/bl2_plat_setup.c
+++ b/plat/st/stm32mp2/bl2_plat_setup.c
@@ -385,6 +385,11 @@
 		break;
 
 	case BL33_IMAGE_ID:
+#if PSA_FWU_SUPPORT
+		stm32_fwu_set_boot_idx();
+#endif /* PSA_FWU_SUPPORT */
+		break;
+
 	default:
 		/* Do nothing in default case */
 		break;
diff --git a/plat/st/stm32mp2/include/stm32mp2_smc.h b/plat/st/stm32mp2/include/stm32mp2_smc.h
new file mode 100644
index 0000000..3bf6a84
--- /dev/null
+++ b/plat/st/stm32mp2/include/stm32mp2_smc.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP2_SMC_H
+#define STM32MP2_SMC_H
+
+#define STM32_COMMON_SIP_NUM_CALLS			1U
+
+/*
+ * STM32_SIP_SMC_STGEN_SET_RATE call API
+ * This service is opened to secure world only.
+ *
+ * Argument a0: (input) SMCC ID
+ *		(output) status return code
+ * Argument a1: (input) Frequency to set (given by sender)
+ */
+#define STM32_SIP_SMC_STGEN_SET_RATE                    0x82000000
+
+#endif /* STM32MP2_SMC_H */
diff --git a/plat/st/stm32mp2/platform.mk b/plat/st/stm32mp2/platform.mk
index 25ae593..a9f8d8f 100644
--- a/plat/st/stm32mp2/platform.mk
+++ b/plat/st/stm32mp2/platform.mk
@@ -202,6 +202,13 @@
 # Generic PSCI
 BL31_SOURCES			+=	plat/common/plat_psci_common.c
 
+BL31_SOURCES			+=	plat/st/common/stm32mp_svc_setup.c			\
+					plat/st/stm32mp2/services/stgen_svc.c			\
+					plat/st/stm32mp2/services/stm32mp2_svc_setup.c
+
+# Arm Archtecture services
+BL31_SOURCES			+=	services/arm_arch_svc/arm_arch_svc_setup.c
+
 # Compilation rules
 .PHONY: check_ddr_type
 bl2: check_ddr_type
diff --git a/plat/st/stm32mp2/services/stgen_svc.c b/plat/st/stm32mp2/services/stgen_svc.c
new file mode 100644
index 0000000..dada315
--- /dev/null
+++ b/plat/st/stm32mp2/services/stgen_svc.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "stgen_svc.h"
+#include <stm32mp2_smc.h>
+#include <stm32mp_common.h>
+#include <stm32mp_svc_setup.h>
+
+/*
+ * This function reads and applies the STGEN frequency value in the STGENC base frequency register,
+ * which is the frequency the system base counter use for our platforms.
+ */
+uint32_t stgen_svc_handler(void)
+{
+	unsigned long freq_to_set = mmio_read_32(STGEN_BASE + CNTFID_OFF);
+
+	VERBOSE("STGEN frequency set to %lu\n", freq_to_set);
+
+	/*
+	 * Update the system counter frequency according to STGEN's base
+	 * counter frequency register
+	 */
+	write_cntfrq_el0((u_register_t)freq_to_set);
+
+	/* Need to update timer with new frequency */
+	generic_delay_timer_init();
+
+	return STM32_SMC_OK;
+}
diff --git a/plat/st/stm32mp2/services/stgen_svc.h b/plat/st/stm32mp2/services/stgen_svc.h
new file mode 100644
index 0000000..98c2304
--- /dev/null
+++ b/plat/st/stm32mp2/services/stgen_svc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STGEN_SVC_H
+#define STGEN_SVC_H
+
+uint32_t stgen_svc_handler(void);
+
+#endif /* STGEN_SVC_H */
diff --git a/plat/st/stm32mp2/services/stm32mp2_svc_setup.c b/plat/st/stm32mp2/services/stm32mp2_svc_setup.c
new file mode 100644
index 0000000..1162757
--- /dev/null
+++ b/plat/st/stm32mp2/services/stm32mp2_svc_setup.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <stm32mp2_smc.h>
+#include <stm32mp_svc_setup.h>
+
+#include "stgen_svc.h"
+
+/*
+ * Platform-level Standard Service SIP SMC handler. This handler will dispatch
+ * the SMC to the correct feature handler.
+ */
+void plat_svc_smc_handler(uint32_t smc_fid, u_register_t x1,
+			  u_register_t x2, u_register_t x3,
+			  u_register_t x4, uint32_t *ret1,
+			  uint32_t *ret2, bool *ret2_enabled,
+			  u_register_t flags)
+{
+	switch (smc_fid) {
+	case STM32_SIP_SVC_CALL_COUNT:
+		*ret1 = STM32_COMMON_SIP_NUM_CALLS;
+		break;
+	case STM32_SIP_SMC_STGEN_SET_RATE:
+		if (!is_caller_secure(flags)) {
+			*ret1 = STM32_SMC_FAILED;
+			break;
+		}
+
+		*ret1 = stgen_svc_handler();
+		break;
+	default:
+		WARN("Unimplemented STM32MP2 Service Call: 0x%x\n", smc_fid);
+		*ret1 = STM32_SMC_NOT_SUPPORTED;
+		break;
+	}
+}
diff --git a/plat/st/stm32mp2/stm32mp2_private.c b/plat/st/stm32mp2/stm32mp2_private.c
index 5be4c5a..ea9d2fc 100644
--- a/plat/st/stm32mp2/stm32mp2_private.c
+++ b/plat/st/stm32mp2/stm32mp2_private.c
@@ -10,6 +10,7 @@
 
 #include <platform_def.h>
 
+#define BKPR_FWU_INFO	48U
 #define BKPR_BOOT_MODE	96U
 
 #if defined(IMAGE_BL31)
@@ -328,6 +329,13 @@
 	return tamp_bkpr(BKPR_BOOT_MODE);
 }
 
+#if PSA_FWU_SUPPORT
+uintptr_t stm32_get_bkpr_fwu_info_addr(void)
+{
+	return tamp_bkpr(BKPR_FWU_INFO);
+}
+#endif /* PSA_FWU_SUPPORT */
+
 uintptr_t stm32_ddrdbg_get_base(void)
 {
 	return DDRDBG_BASE;
diff --git a/tools/encrypt_fw/src/main.c b/tools/encrypt_fw/src/main.c
index 6e43e73..b6246f6 100644
--- a/tools/encrypt_fw/src/main.c
+++ b/tools/encrypt_fw/src/main.c
@@ -26,7 +26,9 @@
 
 /* Global options */
 
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
 static const char build_msg[] = "Built : " __TIME__ ", " __DATE__;
+#endif
 
 static char *key_algs_str[] = {
 	[KEY_ALG_GCM] = "gcm",
diff --git a/tools/tlc/tests/conftest.py b/tools/tlc/tests/conftest.py
index b8f88b5..93e44a9 100644
--- a/tools/tlc/tests/conftest.py
+++ b/tools/tlc/tests/conftest.py
@@ -9,6 +9,8 @@
 
 """ Common configurations and fixtures for test environment."""
 
+from random import randint
+
 import pytest
 import yaml
 from click.testing import CliRunner
@@ -16,6 +18,10 @@
 from tlc.cli import cli
 
 
+def generate_random_bytes(n):
+    return bytes([randint(0, 255) for _ in range(n)])
+
+
 @pytest.fixture
 def tmptlstr(tmpdir):
     return tmpdir.join("tl.bin").strpath
@@ -63,10 +69,27 @@
 def tlcrunner(tmptlstr):
     runner = CliRunner()
     with runner.isolated_filesystem():
-        runner.invoke(cli, ["create", tmptlstr])
+        runner.invoke(cli, ["create", "--size", 0x1F000, tmptlstr])
     return runner
 
 
 @pytest.fixture
 def tlc_entries(tmpfdt):
     return [(0, "/dev/null"), (1, tmpfdt.strpath), (0x102, tmpfdt.strpath)]
+
+
+@pytest.fixture
+def random_entry():
+    def _random_entry(max_size):
+        return randint(0, 0xFFFFFF), generate_random_bytes(randint(0, max_size))
+
+    return _random_entry
+
+
+@pytest.fixture
+def random_entries(random_entry):
+    def _random_entries(n=5, max_size=0x100):
+        for _ in range(n):
+            yield random_entry(max_size)
+
+    return _random_entries
diff --git a/tools/tlc/tests/test_cli.py b/tools/tlc/tests/test_cli.py
index a5ef30e..ebe1f6a 100644
--- a/tools/tlc/tests/test_cli.py
+++ b/tools/tlc/tests/test_cli.py
@@ -17,6 +17,7 @@
 import pytest
 import yaml
 from click.testing import CliRunner
+from conftest import generate_random_bytes
 
 from tlc.cli import cli
 from tlc.te import TransferEntry
@@ -32,6 +33,22 @@
     assert TransferList.fromfile(test_file) is not None
 
 
+@pytest.mark.parametrize("align", [4, 6, 12, 13])
+def test_create_with_align(align, tlcrunner, tmpdir):
+    tl_file = tmpdir.join("tl.bin").strpath
+    tlcrunner.invoke(cli, ["create", "-s", "10000", "-a", align, tl_file])
+
+    blob = tmpdir.join("blob.bin")
+
+    blob.write_binary(generate_random_bytes(0x200))
+    tlcrunner.invoke(cli, ["add", "--entry", 1, blob.strpath, tl_file])
+
+    tl = TransferList.fromfile(tl_file)
+    te = tl.entries[-1]
+    assert tl.alignment == align
+    assert (te.offset + te.hdr_size) % (1 << align) == 0
+
+
 def test_create_with_fdt(tmpdir):
     runner = CliRunner()
     fdt = tmpdir.join("fdt.dtb")
@@ -69,6 +86,20 @@
     assert len(tl.entries) == len(tlc_entries)
 
 
+@pytest.mark.parametrize("align", [4, 6, 12, 13])
+def test_cli_add_entry_with_align(align, tlcrunner, tmpdir, tmptlstr):
+    blob = tmpdir.join("blob.bin")
+    blob.write_binary(bytes(0x100))
+
+    tlcrunner.invoke(cli, ["add", "--align", align, "--entry", 1, blob, tmptlstr])
+    tl = TransferList.fromfile(tmptlstr)
+    te = tl.entries[-1]
+
+    print(tl, *(te for te in tl.entries), sep="\n---------------\n")
+    assert (te.offset + te.hdr_size) % (1 << align) == 0
+    assert tl.alignment == align
+
+
 def test_info(tlcrunner, tmptlstr, tmpfdt):
     tlcrunner.invoke(cli, ["add", "--entry", "0", "/dev/null", tmptlstr])
     tlcrunner.invoke(cli, ["add", "--fdt", tmpfdt.strpath, tmptlstr])
diff --git a/tools/tlc/tests/test_transfer_list.py b/tools/tlc/tests/test_transfer_list.py
index e8c430e..6900b41 100644
--- a/tools/tlc/tests/test_transfer_list.py
+++ b/tools/tlc/tests/test_transfer_list.py
@@ -9,6 +9,7 @@
 """Contains unit tests for the types TransferEntry and TransferList."""
 
 import math
+from random import randint
 
 import pytest
 
@@ -49,16 +50,40 @@
         assert tl.checksum == csum
 
 
-@pytest.mark.parametrize(("tag_id", "data"), test_entries)
-def test_add_transfer_entry(tag_id, data):
+def test_add_transfer_entry(random_entries):
     tl = TransferList(0x1000)
-    te = TransferEntry(tag_id, len(data), data)
 
-    tl.add_transfer_entry(tag_id, data)
-
+    # Add a single entry and check it's in the list of entries
+    te = tl.add_transfer_entry(1, bytes(100))
     assert te in tl.entries
-    assert tl.size == TransferList.hdr_size + te.size
+    assert tl.size % 8 == 0
+
+    # Add a range of tag id's
+    for id, data in random_entries(50, 1):
+        te = tl.add_transfer_entry(id, data)
+        assert te in tl.entries
+        assert tl.size % 8 == 0
+
+
+@pytest.mark.parametrize("align", [4, 6, 12, 13])
+def test_add_transfer_entry_with_align(align, random_entries, random_entry):
+    tl = TransferList(0xF00000)
+    id, data = random_entry(4)
 
+    tl.add_transfer_entry(id, data)
+
+    # Add an entry with a larger alignment requirement
+    _, data = random_entry(4)
+    te = tl.add_transfer_entry(1, data, data_align=align)
+    assert (te.offset + te.hdr_size) % (1 << align) == 0
+    assert tl.alignment == align
+
+    # Add some more entries and ensure the alignment is preserved
+    for id, data in random_entries(5, 0x200):
+        te = tl.add_transfer_entry(id, data, data_align=align)
+        assert (te.offset + te.hdr_size) % (1 << align) == 0
+        assert tl.alignment == align
+
 
 @pytest.mark.parametrize(
     ("tag_id", "data"),
@@ -88,13 +113,20 @@
     assert te.sum_of_bytes == csum
 
 
-@pytest.mark.parametrize(("tag_id", "data"), test_entries)
-def test_calculate_tl_checksum(tag_id, data):
+def test_calc_tl_checksum(tmpdir, random_entries):
+    tl_file = tmpdir.join("tl.bin")
+
     tl = TransferList(0x1000)
 
-    tl.add_transfer_entry(tag_id, data)
-    assert tl.sum_of_bytes() == 0
+    for id, data in random_entries(10):
+        tl.add_transfer_entry(id, data)
 
+    assert sum(tl.to_bytes()) % 256 == 0
+
+    # Write the transfer list to a file and check that the sum of bytes is 0
+    tl.write_to_file(tl_file)
+    assert sum(tl_file.read_binary()) % 256 == 0
+
 
 def test_empty_transfer_list_blob(tmpdir):
     """Check that we can correctly create a transfer list header."""
@@ -125,28 +157,44 @@
         assert f.read(te.data_size) == te.data
 
 
-def test_multiple_te_transfer_list(tmpdir):
+def test_write_multiple_tes_to_file(tmpdir, random_entries, random_entry):
     """Check that we can create a TL with multiple TE's."""
     test_file = tmpdir.join("test_tl_blob.bin")
-    tl = TransferList(0x1000)
+    tl = TransferList(0x4000)
+    _test_entries = list(random_entries())
 
-    for tag_id, data in test_entries:
+    for tag_id, data in _test_entries:
         tl.add_transfer_entry(tag_id, data)
 
+    # Add a few entries with special alignment requirements
+    blob_id, blob = random_entry(0x200)
+    tl.add_transfer_entry(blob_id, blob, data_align=12)
+
     tl.write_to_file(test_file)
 
     with open(test_file, "rb") as f:
         assert f.read(tl.hdr_size) == tl.header_to_bytes()
         # Ensure that TE's have the correct alignment
-        for tag_id, data in test_entries:
-            f.seek(int(math.ceil(f.tell() / 2**tl.alignment) * 2**tl.alignment))
-            print(f.tell())
+        for tag_id, data in _test_entries:
+            f.seek(int(math.ceil(f.tell() / 8) * 8))
+
             assert int.from_bytes(f.read(3), "little") == tag_id
             assert int.from_bytes(f.read(1), "little") == TransferEntry.hdr_size
             # Make sure the data in the TE matches the data in the original case
             data_size = int.from_bytes(f.read(4), "little")
             assert f.read(data_size) == data
 
+        f.seek(int(math.ceil(f.tell() / (1 << 12)) * (1 << 12)) - 8)
+        assert int.from_bytes(f.read(3), "little") == blob_id
+        assert int.from_bytes(f.read(1), "little") == TransferEntry.hdr_size
+        # Make sure the data in the TE matches the data in the original case
+        data_size = int.from_bytes(f.read(4), "little")
+        assert f.read(data_size) == blob
+
+        # padding is added to align TE's, make sure padding is added to the size of
+        # the TL by checking we don't overflow.
+        assert f.tell() <= tl.size
+
 
 def test_read_empty_transfer_list_from_file(tmpdir):
     test_file = tmpdir.join("test_tl_blob.bin")
@@ -196,19 +244,17 @@
     assert tl.sum_of_bytes() == 0
 
 
-@pytest.mark.parametrize("tag", [tag for tag, _ in test_entries])
-def test_remove_tag_from_file(tag):
-    tl = TransferList(0x1000)
-
-    for tag_id, data in test_entries:
-        tl.add_transfer_entry(tag_id, data)
+def test_remove_tag(random_entry):
+    """Adds a transfer entry and remove it, size == transfer list header."""
+    tl = TransferList(0x100)
+    id, data = random_entry(tl.total_size // 2)
 
-    removed_entries = list(filter(lambda te: te.id == tag, tl.entries))
-    original_size = tl.size
-    tl.remove_tag(tag)
+    te = tl.add_transfer_entry(id, data)
+    assert te in tl.entries
 
-    assert not any(tag == te.id for te in tl.entries)
-    assert tl.size == original_size - sum(map(lambda te: te.size, removed_entries))
+    tl.remove_tag(id)
+    assert not tl.get_entry(id) and te not in tl.entries
+    assert tl.size == tl.hdr_size
 
 
 def test_get_fdt_offset(tmpdir):
diff --git a/tools/tlc/tlc/cli.py b/tools/tlc/tlc/cli.py
index 3d60938..431af04 100644
--- a/tools/tlc/tlc/cli.py
+++ b/tools/tlc/tlc/cli.py
@@ -27,6 +27,14 @@
 @cli.command()
 @click.argument("filename", type=click.Path(dir_okay=False))
 @click.option(
+    "-a",
+    "--align",
+    type=int,
+    default=3,
+    show_default=True,
+    help="Set alignment in powers of 2 (e.g., -a 3 for 8 byte alignment).",
+)
+@click.option(
     "-s", "--size", default=0x1000, type=int, help="Maximum size of the Transfer List"
 )
 @click.option(
@@ -51,7 +59,7 @@
     type=click.Path(exists=True),
     help="Create the transfer list from a YAML config file.",
 )
-def create(filename, size, fdt, entry, flags, from_yaml):
+def create(filename, align, size, fdt, entry, flags, from_yaml):
     """Create a new Transfer List."""
     try:
         if from_yaml:
@@ -60,12 +68,12 @@
 
             tl = TransferList.from_dict(config)
         else:
-            tl = TransferList(size)
+            tl = TransferList(size, flags=flags, alignment=align)
 
             entry = (*entry, (1, fdt)) if fdt else entry
 
             for id, path in entry:
-                tl.add_transfer_entry_from_file(id, path)
+                tl.add_transfer_entry_from_file(id, path, data_align=align)
     except MemoryError as mem_excp:
         raise MemoryError(
             "TL max size exceeded, consider increasing with the option -s"
@@ -133,19 +141,24 @@
 
 
 @cli.command()
-@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
+@click.option(
+    "-a",
+    "--align",
+    type=int,
+    help="Set alignment in powers of 2 (e.g., -a 3 for 8 byte alignment).",
+)
 @click.option(
     "--entry",
     type=(int, click.Path(exists=True)),
     multiple=True,
     help="A tag ID and the corresponding path to a binary blob in the form <id> <path-to-blob>.",
 )
-def add(filename, entry):
+@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
+def add(align, entry, filename):
     """Update an existing Transfer List with given images."""
     tl = TransferList.fromfile(filename)
-
     for id, path in entry:
-        tl.add_transfer_entry_from_file(id, path)
+        tl.add_transfer_entry_from_file(id, path, data_align=align)
 
     tl.write_to_file(filename)
 
diff --git a/tools/tlc/tlc/te.py b/tools/tlc/tlc/te.py
index cf7aa67..0b6b532 100644
--- a/tools/tlc/tlc/te.py
+++ b/tools/tlc/tlc/te.py
@@ -48,7 +48,10 @@
 
     @property
     def sum_of_bytes(self) -> int:
-        return (sum(self.header_to_bytes()) + sum(self.data)) % 256
+        return sum(self.to_bytes()) % 256
+
+    def to_bytes(self) -> bytes:
+        return self.header_to_bytes() + self.data
 
     def header_to_bytes(self) -> bytes:
         return self.id.to_bytes(3, "little") + struct.pack(
diff --git a/tools/tlc/tlc/tl.py b/tools/tlc/tlc/tl.py
index 98d2205..dfbea9f 100644
--- a/tools/tlc/tlc/tl.py
+++ b/tools/tlc/tlc/tl.py
@@ -83,13 +83,17 @@
     hdr_size = 0x18
     signature = 0x4A0FB10B
     version = 1
+    granule = 8
 
     def __init__(
-        self, max_size: int = hdr_size, flags: int = TRANSFER_LIST_ENABLE_CHECKSUM
+        self,
+        max_size: int = hdr_size,
+        flags: int = TRANSFER_LIST_ENABLE_CHECKSUM,
+        alignment: int = 3,
     ) -> None:
         assert max_size >= self.hdr_size
         self.checksum: int = 0
-        self.alignment: int = 3
+        self.alignment: int = alignment
         self.size = self.hdr_size
         self.total_size = max_size
         self.flags = flags
@@ -138,16 +142,15 @@
                     # the 3-byte wide ID as a 4-byte uint, shift out this padding
                     # once we have the id.
                     te_base = f.tell()
-                    (id, hdr_size, data_size) = struct.unpack(
+                    (id, _, data_size) = struct.unpack(
                         TransferEntry.encoding[0] + "I" + TransferEntry.encoding[1:],
                         b"\x00" + f.read(TransferEntry.hdr_size),
                     )
 
                     id >>= 8
-
                     te = tl.add_transfer_entry(id, f.read(data_size))
                     te.offset = te_base
-                    f.seek(align(te_base + hdr_size + data_size, 2**tl.alignment))
+                    f.seek(align(f.tell(), tl.granule))
 
         return tl
 
@@ -163,10 +166,14 @@
         # get settings from config and set defaults
         max_size = config.get("max_size", 0x1000)
         has_checksum = config.get("has_checksum", True)
+        align = config.get("alignment", None)
 
         flags = TRANSFER_LIST_ENABLE_CHECKSUM if has_checksum else 0
 
-        tl = cls(max_size, flags)
+        if align:
+            tl = cls(max_size, flags, alignment=align)
+        else:
+            tl = cls(max_size, flags)
 
         for entry in config["entries"]:
             tl.add_transfer_entry_from_dict(entry)
@@ -189,13 +196,15 @@
 
     def update_checksum(self) -> None:
         """Calculates the checksum based on the sum of bytes."""
-        self.checksum = 256 - ((self.sum_of_bytes() - self.checksum) % 256)
+        self.checksum = (256 - (self.sum_of_bytes() - self.checksum)) % 256
+        assert self.checksum <= 0xFF
+
+    def to_bytes(self) -> bytes:
+        return self.header_to_bytes() + b"".join([te.to_bytes() for te in self.entries])
 
     def sum_of_bytes(self) -> int:
         """Sum of all bytes between the base address and the end of that last TE (modulo 0xff)."""
-        return (
-            sum(self.header_to_bytes()) + sum(te.sum_of_bytes for te in self.entries)
-        ) % 256
+        return (sum(self.to_bytes())) % 256
 
     def get_entry(self, tag_id: int) -> Optional[TransferEntry]:
         for te in self.entries:
@@ -213,18 +222,35 @@
 
         return te.offset + te.hdr_size
 
-    def add_transfer_entry(self, tag_id: int, data: bytes) -> TransferEntry:
+    def add_transfer_entry(
+        self, tag_id: int, data: bytes, data_align: int = 0
+    ) -> TransferEntry:
         """Appends a TransferEntry into the internal list of TE's."""
+        data_offset = TransferEntry.hdr_size + self.size
+        data_align = self.alignment if not data_align else data_align
+
+        aligned_data_offset = align(data_offset, 1 << data_align)
+
+        if tag_id != 0 and data_offset != aligned_data_offset:
+            void_len = aligned_data_offset - data_offset - TransferEntry.hdr_size
+            self.add_transfer_entry(0, bytes(void_len))
+
+        assert align(self.size, self.granule)
+
         if not (self.total_size >= self.size + TransferEntry.hdr_size + len(data)):
             raise MemoryError(
                 f"TL size has exceeded the maximum allocation {self.total_size}."
             )
-        else:
-            te = TransferEntry(tag_id, len(data), data)
-            self.entries.append(te)
-            self.size += te.size
-            self.update_checksum()
-            return te
+
+        te = TransferEntry(tag_id, len(data), data, offset=self.size)
+        self.entries.append(te)
+
+        self.size += align(te.size, self.granule)
+        if data_align > self.alignment:
+            self.alignment = data_align
+
+        self.update_checksum()
+        return te
 
     def add_transfer_entry_from_struct_format(
         self, tag_id: int, struct_format: str, *args: Any
@@ -305,32 +331,40 @@
         tag_id = entry["tag_id"]
         if tag_id in tag_name_to_tag_id:
             tag_id = tag_name_to_tag_id[tag_id]
-        te_format = transfer_entry_formats[tag_id]
-        tag_name = te_format["tag_name"]
-
-        if "blob_file_path" in entry:
-            return self.add_transfer_entry_from_file(tag_id, entry["blob_file_path"])
-        elif tag_name == "tpm_event_log_table":
-            with open(entry["event_log"], "rb") as f:
-                event_log_data = f.read()
 
-            flags_bytes = entry["flags"].to_bytes(4, "little")
-            data = flags_bytes + event_log_data
+        align = entry.get("alignment", None)
 
-            return self.add_transfer_entry(tag_id, data)
-        elif tag_name == "exec_ep_info":
-            return self.add_entry_point_info_transfer_entry(entry)
-        elif "format" in te_format and "fields" in te_format:
-            fields = [entry[field] for field in te_format["fields"]]
-            return self.add_transfer_entry_from_struct_format(
-                tag_id, te_format["format"], *fields
+        if "blob_file_path" in entry:
+            return self.add_transfer_entry_from_file(
+                tag_id, entry["blob_file_path"], data_align=align
             )
         else:
-            raise ValueError(f"Invalid transfer entry {entry}.")
+            te_format = transfer_entry_formats[tag_id]
+            tag_name = te_format["tag_name"]
 
-    def add_transfer_entry_from_file(self, tag_id: int, path: Path) -> TransferEntry:
+            if tag_name == "tpm_event_log_table":
+                with open(entry["event_log"], "rb") as f:
+                    event_log_data = f.read()
+
+                flags_bytes = entry["flags"].to_bytes(4, "little")
+                data = flags_bytes + event_log_data
+
+                return self.add_transfer_entry(tag_id, data, data_align=align)
+            elif tag_name == "exec_ep_info":
+                return self.add_entry_point_info_transfer_entry(entry)
+            elif "format" in te_format and "fields" in te_format:
+                fields = [entry[field] for field in te_format["fields"]]
+                return self.add_transfer_entry_from_struct_format(
+                    tag_id, te_format["format"], *fields
+                )
+            else:
+                raise ValueError(f"Invalid transfer entry {entry}.")
+
+    def add_transfer_entry_from_file(
+        self, tag_id: int, path: Path, data_align: int = 0
+    ) -> TransferEntry:
         with open(path, "rb") as f:
-            return self.add_transfer_entry(tag_id, f.read())
+            return self.add_transfer_entry(tag_id, f.read(), data_align=data_align)
 
     def write_to_file(self, file: Path) -> None:
         """Write the contents of the TL to a file."""
@@ -338,20 +372,11 @@
             f.write(self.header_to_bytes())
             for te in self.entries:
                 assert f.tell() + te.hdr_size + te.data_size < self.total_size
-                te_base = f.tell()
+
                 f.write(te.header_to_bytes())
                 f.write(te.data)
-                # Ensure the next TE has the correct alignment
-                f.write(
-                    bytes(
-                        (
-                            align(
-                                te_base + te.hdr_size + te.data_size, 2**self.alignment
-                            )
-                            - f.tell()
-                        )
-                    )
-                )
+                # Ensure the next TE is at an 8-byte aligned address
+                f.write(bytes((align(f.tell(), self.granule) - f.tell())))
 
     def remove_tag(self, tag: int) -> None:
         self.entries = list(filter(lambda te: te.id != tag, self.entries))