Merge "feat(context-mgmt): introduce EL3/root context" into integration
diff --git a/Makefile b/Makefile
index 179e07a..ea4966d 100644
--- a/Makefile
+++ b/Makefile
@@ -1177,6 +1177,7 @@
 	HW_ASSISTED_COHERENCY \
 	MEASURED_BOOT \
 	DICE_PROTECTION_ENVIRONMENT \
+	RMMD_ENABLE_EL3_TOKEN_SIGN \
 	DRTM_SUPPORT \
 	NS_TIMER_SWITCH \
 	OVERRIDE_LIBC \
@@ -1263,11 +1264,13 @@
 	ENABLE_FEAT_RNG_TRAP \
 	ENABLE_FEAT_SEL2 \
 	ENABLE_FEAT_TCR2 \
+	ENABLE_FEAT_THE \
 	ENABLE_FEAT_SB \
 	ENABLE_FEAT_S2PIE \
 	ENABLE_FEAT_S1PIE \
 	ENABLE_FEAT_S2POE \
 	ENABLE_FEAT_S1POE \
+	ENABLE_FEAT_SCTLR2 \
 	ENABLE_FEAT_GCS \
 	ENABLE_FEAT_VHE \
 	ENABLE_FEAT_MPAM \
@@ -1331,6 +1334,7 @@
 	ENABLE_PMF \
 	ENABLE_PSCI_STAT \
 	ENABLE_RME \
+	RMMD_ENABLE_EL3_TOKEN_SIGN \
 	ENABLE_RUNTIME_INSTRUMENTATION \
 	ENABLE_SME_FOR_NS \
 	ENABLE_SME2_FOR_NS \
@@ -1419,10 +1423,12 @@
 	ENABLE_FEAT_CSV2_3 \
 	ENABLE_FEAT_PAN \
 	ENABLE_FEAT_TCR2 \
+	ENABLE_FEAT_THE \
 	ENABLE_FEAT_S2PIE \
 	ENABLE_FEAT_S1PIE \
 	ENABLE_FEAT_S2POE \
 	ENABLE_FEAT_S1POE \
+	ENABLE_FEAT_SCTLR2 \
 	ENABLE_FEAT_GCS \
 	ENABLE_FEAT_MTE2 \
 	FEATURE_DETECTION \
diff --git a/changelog.yaml b/changelog.yaml
index 5224441..3591f02 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -900,6 +900,9 @@
       - title: Console
         scope: console
 
+      - title: Delay Timer
+        scope: delay-timer
+
       - title: Generic Clock
         scope: clk
 
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 9b9f7b4..e63eec4 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -257,6 +257,18 @@
 
 }
 
+static unsigned int read_feat_the_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64pfr1_el1(), ID_AA64PFR1_EL1_THE_SHIFT,
+			     ID_AA64PFR1_EL1_THE_MASK);
+}
+
+static unsigned int read_feat_sctlr2_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64mmfr3_el1(), ID_AA64MMFR3_EL1_SCTLR2_SHIFT,
+			     ID_AA64MMFR3_EL1_SCTLR2_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
@@ -365,6 +377,10 @@
 		      "CSV2_3", 3, 3);
 	check_feature(ENABLE_FEAT_DEBUGV8P9, read_feat_debugv8p9_id_field(),
 			"DEBUGV8P9", 11, 11);
+	check_feature(ENABLE_FEAT_THE, read_feat_the_id_field(),
+			"THE", 1, 1);
+	check_feature(ENABLE_FEAT_SCTLR2, read_feat_sctlr2_id_field(),
+			"SCTLR2", 1, 1);
 
 	/* v9.0 features */
 	check_feature(ENABLE_BRBE_FOR_NS, read_feat_brbe_id_field(),
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index 7fe58f8..253b18d 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -72,6 +72,8 @@
 +-----------------+---------------------------+------------------------------+
 | v2.12           | 4th week of Nov '24       | 2nd week of Nov '24          |
 +-----------------+---------------------------+------------------------------+
+| v2.13           | 4th week of May '25       | 2nd week of May '25          |
++-----------------+---------------------------+------------------------------+
 
 Removal of Deprecated Interfaces
 --------------------------------
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 203bf0f..7776f5b 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -455,6 +455,22 @@
    the values 0 to 2, to align  with the ``ENABLE_FEAT`` mechanism.
    Default value is ``0``.
 
+-  ``ENABLE_FEAT_THE``: Numeric value to enable support for FEAT_THE
+   (Translation Hardening Extension) at EL2 and below, setting the bit
+   SCR_EL3.RCWMASKEn in EL3 to allow access to RCWMASK_EL1 and RCWSMASK_EL1
+   registers and context switch them.
+   Its an optional architectural feature and is available from v8.8 and upwards.
+   This flag can take the values 0 to 2, to align  with the ``ENABLE_FEAT``
+   mechanism. Default value is ``0``.
+
+-  ``ENABLE_FEAT_SCTLR2``: Numeric value to enable support for FEAT_SCTLR2
+   (Extension to SCTLR_ELx) at EL2 and below, setting the bit
+   SCR_EL3.SCTLR2En in EL3 to allow access to SCTLR2_ELx registers and
+   context switch them. This feature is OPTIONAL from Armv8.0 implementations
+   and mandatory in Armv8.9 implementations.
+   This flag can take the values 0 to 2, to align  with the ``ENABLE_FEAT``
+   mechanism. Default value is ``0``.
+
 -  ``ENABLE_LTO``: Boolean option to enable Link Time Optimization (LTO)
    support in GCC for TF-A. This option is currently only supported for
    AArch64. Default is 0.
diff --git a/drivers/arm/dcc/dcc_console.c b/drivers/arm/dcc/dcc_console.c
index 19c3450..841c1fd 100644
--- a/drivers/arm/dcc/dcc_console.c
+++ b/drivers/arm/dcc/dcc_console.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2015-2021, Xilinx Inc.
+ * Copyright (c) 2015-2022, Xilinx Inc.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  * Written by Michal Simek.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -45,7 +46,7 @@
 #define TIMEOUT_COUNT_US	U(0x10624)
 
 struct dcc_console {
-	struct console console;
+	console_t console;
 };
 
 static inline uint32_t __dcc_getstatus(void)
@@ -147,13 +148,14 @@
 	},
 };
 
-int console_dcc_register(void)
+int console_dcc_register(console_t *console)
 {
-	return console_register(&dcc_console.console);
+	memcpy(console, &dcc_console.console, sizeof(console_t));
+	return console_register(console);
 }
 
-void console_dcc_unregister(void)
+void console_dcc_unregister(console_t *console)
 {
-	dcc_console_flush(&dcc_console.console);
-	(void)console_unregister(&dcc_console.console);
+	dcc_console_flush(console);
+	(void)console_unregister(console);
 }
diff --git a/drivers/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c
index a3fd7bf..bdbbbf6 100644
--- a/drivers/delay_timer/delay_timer.c
+++ b/drivers/delay_timer/delay_timer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -80,3 +80,25 @@
 
 	timer_ops = ops_ptr;
 }
+
+/***********************************************************
+ * Initialize the timer in us
+ ***********************************************************/
+uint64_t timeout_init_us(uint32_t usec)
+{
+	assert(timer_ops != NULL);
+	assert(timer_ops->timeout_init_us != NULL);
+
+	return timer_ops->timeout_init_us(usec);
+}
+
+/***********************************************************
+ * check the given timeout elapsed or not.
+ ***********************************************************/
+bool timeout_elapsed(uint64_t cnt)
+{
+	assert(timer_ops != NULL);
+	assert(timer_ops->timeout_elapsed != NULL);
+
+	return timer_ops->timeout_elapsed(cnt);
+}
diff --git a/drivers/delay_timer/generic_delay_timer.c b/drivers/delay_timer/generic_delay_timer.c
index ca522e0..0407e38 100644
--- a/drivers/delay_timer/generic_delay_timer.c
+++ b/drivers/delay_timer/generic_delay_timer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -18,7 +18,26 @@
 
 static timer_ops_t ops;
 
-static uint32_t get_timer_value(void)
+static uint64_t timeout_cnt_us2cnt(uint32_t us)
+{
+	return ((uint64_t)us * (uint64_t)read_cntfrq_el0()) / 1000000ULL;
+}
+
+static uint64_t generic_delay_timeout_init_us(uint32_t us)
+{
+	uint64_t cnt = timeout_cnt_us2cnt(us);
+
+	cnt += read_cntpct_el0();
+
+	return cnt;
+}
+
+static bool generic_delay_timeout_elapsed(uint64_t expire_cnt)
+{
+	return read_cntpct_el0() > expire_cnt;
+}
+
+static uint32_t generic_delay_get_timer_value(void)
 {
 	/*
 	 * Generic delay timer implementation expects the timer to be a down
@@ -31,9 +50,11 @@
 
 void generic_delay_timer_init_args(uint32_t mult, uint32_t div)
 {
-	ops.get_timer_value	= get_timer_value;
+	ops.get_timer_value	= generic_delay_get_timer_value;
 	ops.clk_mult		= mult;
 	ops.clk_div		= div;
+	ops.timeout_init_us	= generic_delay_timeout_init_us;
+	ops.timeout_elapsed	= generic_delay_timeout_elapsed;
 
 	timer_init(&ops);
 
@@ -59,4 +80,3 @@
 
 	generic_delay_timer_init_args(mult, div);
 }
-
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index d8ad881..8145616 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -406,6 +406,10 @@
 #define ID_AA64MMFR3_EL1_S1PIE_SHIFT		U(8)
 #define ID_AA64MMFR3_EL1_S1PIE_MASK		ULL(0xf)
 
+#define ID_AA64MMFR3_EL1_SCTLR2_SHIFT		U(4)
+#define ID_AA64MMFR3_EL1_SCTLR2_MASK		ULL(0xf)
+#define SCTLR2_IMPLEMENTED			ULL(1)
+
 #define ID_AA64MMFR3_EL1_TCRX_SHIFT		U(0)
 #define ID_AA64MMFR3_EL1_TCRX_MASK		ULL(0xf)
 
@@ -433,6 +437,10 @@
 #define ID_AA64PFR1_EL1_GCS_MASK	ULL(0xf)
 #define GCS_IMPLEMENTED			ULL(1)
 
+#define ID_AA64PFR1_EL1_THE_SHIFT	U(48)
+#define ID_AA64PFR1_EL1_THE_MASK	ULL(0xf)
+#define THE_IMPLEMENTED			ULL(1)
+
 #define RNG_TRAP_IMPLEMENTED		ULL(0x1)
 
 /* ID_AA64PFR2_EL1 definitions */
@@ -589,7 +597,9 @@
 #define SCR_TWEDEL_SHIFT	U(30)
 #define SCR_TWEDEL_MASK		ULL(0xf)
 #define SCR_PIEN_BIT		(UL(1) << 45)
+#define SCR_SCTLR2En_BIT	(UL(1) << 44)
 #define SCR_TCR2EN_BIT		(UL(1) << 43)
+#define SCR_RCWMASKEn_BIT	(UL(1) << 42)
 #define SCR_TRNDR_BIT		(UL(1) << 40)
 #define SCR_GCSEn_BIT		(UL(1) << 39)
 #define SCR_HXEn_BIT		(UL(1) << 38)
@@ -1473,6 +1483,18 @@
 #define TRFCR_EL1		S3_0_C1_C2_1
 
 /*******************************************************************************
+ * FEAT_THE - Translation Hardening Extension Registers
+ ******************************************************************************/
+#define RCWMASK_EL1		S3_0_C13_C0_6
+#define RCWSMASK_EL1		S3_0_C13_C0_3
+
+/*******************************************************************************
+ * FEAT_SCTLR2 - Extension to SCTLR_ELx Registers
+ ******************************************************************************/
+#define SCTLR2_EL2		S3_4_C1_C0_3
+#define SCTLR2_EL1		S3_0_C1_C0_3
+
+/*******************************************************************************
  * Definitions for DynamicIQ Shared Unit registers
  ******************************************************************************/
 #define CLUSTERPWRDN_EL1	S3_0_c15_c3_6
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index f03c9d5..de21fea 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -134,6 +134,10 @@
  * +----------------------------+
  * |	FEAT_FGT2		|
  * +----------------------------+
+ * |	FEAT_THE		|
+ * +----------------------------+
+ * |	FEAT_SCTLR2		|
+ * +----------------------------+
  */
 
 __attribute__((always_inline))
@@ -262,6 +266,15 @@
 CREATE_FEATURE_FUNCS(feat_s1pie, id_aa64mmfr3_el1, ID_AA64MMFR3_EL1_S1PIE_SHIFT,
 		     ID_AA64MMFR3_EL1_S1PIE_MASK, 1U, ENABLE_FEAT_S1PIE)
 
+/* FEAT_THE: Translation Hardening Extension */
+CREATE_FEATURE_FUNCS(feat_the, id_aa64pfr1_el1, ID_AA64PFR1_EL1_THE_SHIFT,
+		     ID_AA64PFR1_EL1_THE_MASK, THE_IMPLEMENTED, ENABLE_FEAT_THE)
+
+/* FEAT_SCTLR2 */
+CREATE_FEATURE_FUNCS(feat_sctlr2, id_aa64mmfr3_el1, ID_AA64MMFR3_EL1_SCTLR2_SHIFT,
+		     ID_AA64MMFR3_EL1_SCTLR2_MASK, SCTLR2_IMPLEMENTED,
+		     ENABLE_FEAT_SCTLR2)
+
 __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 a892654..acaa1b8 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -670,6 +670,14 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(gcspr_el1, GCSPR_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(gcspr_el0, GCSPR_EL0)
 
+/* FEAT_THE Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(rcwmask_el1, RCWMASK_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(rcwsmask_el1, RCWSMASK_EL1)
+
+/* FEAT_SCTLR2 Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(sctlr2_el1, SCTLR2_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(sctlr2_el2, SCTLR2_EL2)
+
 /* DynamIQ Control registers */
 DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmcr_el1, CLUSTERPMCR_EL1)
diff --git a/include/drivers/arm/dcc.h b/include/drivers/arm/dcc.h
index 072bed5..7f71932 100644
--- a/include/drivers/arm/dcc.h
+++ b/include/drivers/arm/dcc.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2021,  Xilinx Inc.
+ * Copyright (c) 2021-2022, Xilinx Inc.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,7 +15,7 @@
  * Initialize a new dcc console instance and register it with the console
  * framework.
  */
-int console_dcc_register(void);
-void console_dcc_unregister(void);
+int console_dcc_register(console_t *console);
+void console_dcc_unregister(console_t *console);
 
-#endif /* DCC */
+#endif /* DCC_H */
diff --git a/include/drivers/delay_timer.h b/include/drivers/delay_timer.h
index 20a5543..e9fdfb7 100644
--- a/include/drivers/delay_timer.h
+++ b/include/drivers/delay_timer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2019, Linaro Limited
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -25,27 +25,12 @@
 	uint32_t (*get_timer_value)(void);
 	uint32_t clk_mult;
 	uint32_t clk_div;
+	uint64_t (*timeout_init_us)(uint32_t usec);
+	bool (*timeout_elapsed)(uint64_t cnt);
 } timer_ops_t;
 
-static inline uint64_t timeout_cnt_us2cnt(uint32_t us)
-{
-	return ((uint64_t)us * (uint64_t)read_cntfrq_el0()) / 1000000ULL;
-}
-
-static inline uint64_t timeout_init_us(uint32_t us)
-{
-	uint64_t cnt = timeout_cnt_us2cnt(us);
-
-	cnt += read_cntpct_el0();
-
-	return cnt;
-}
-
-static inline bool timeout_elapsed(uint64_t expire_cnt)
-{
-	return read_cntpct_el0() > expire_cnt;
-}
-
+uint64_t timeout_init_us(uint32_t usec);
+bool timeout_elapsed(uint64_t cnt);
 void mdelay(uint32_t msec);
 void udelay(uint32_t usec);
 void timer_init(const timer_ops_t *ops_ptr);
diff --git a/include/lib/el3_runtime/context_el1.h b/include/lib/el3_runtime/context_el1.h
index 038de25..94af210 100644
--- a/include/lib/el3_runtime/context_el1.h
+++ b/include/lib/el3_runtime/context_el1.h
@@ -107,6 +107,15 @@
 	uint64_t gcspr_el0;
 } el1_gcs_regs_t;
 
+typedef struct el1_the_regs {
+	uint64_t rcwmask_el1;
+	uint64_t rcwsmask_el1;
+} el1_the_regs_t;
+
+typedef struct el1_sctlr2_regs {
+	uint64_t sctlr2_el1;
+} el1_sctlr2_regs_t;
+
 typedef struct el1_sysregs {
 
 	el1_common_regs_t common;
@@ -155,6 +164,14 @@
 	el1_gcs_regs_t gcs;
 #endif
 
+#if ENABLE_FEAT_THE
+	el1_the_regs_t the;
+#endif
+
+#if ENABLE_FEAT_SCTLR2
+	el1_sctlr2_regs_t sctlr2;
+#endif
+
 } el1_sysregs_t;
 
 
@@ -266,6 +283,25 @@
 #define read_el1_ctx_gcs(ctx, reg)		ULL(0)
 #define write_el1_ctx_gcs(ctx, reg, val)
 #endif /* ENABLE_FEAT_GCS */
+
+#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))
+#else
+#define read_el1_ctx_the(ctx, reg)		ULL(0)
+#define write_el1_ctx_the(ctx, reg, val)
+#endif /* ENABLE_FEAT_THE */
+
+#if ENABLE_FEAT_SCTLR2
+#define read_el1_ctx_sctlr2(ctx, reg)		(((ctx)->sctlr2).reg)
+#define write_el1_ctx_sctlr2(ctx, reg, val)	((((ctx)->sctlr2).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el1_ctx_sctlr2(ctx, reg)		ULL(0)
+#define write_el1_ctx_sctlr2(ctx, reg, val)
+#endif /* ENABLE_FEAT_SCTLR2 */
+
 /******************************************************************************/
 #endif /* __ASSEMBLER__ */
 
diff --git a/include/lib/el3_runtime/context_el2.h b/include/lib/el3_runtime/context_el2.h
index 14c1fb6..ad0b68f 100644
--- a/include/lib/el3_runtime/context_el2.h
+++ b/include/lib/el3_runtime/context_el2.h
@@ -135,6 +135,10 @@
 	uint64_t mpamvpmv_el2;
 } el2_mpam_regs_t;
 
+typedef struct el2_sctlr2_regs {
+	uint64_t sctlr2_el2;
+} el2_sctlr2_regs_t;
+
 typedef struct el2_sysregs {
 
 	el2_common_regs_t common;
@@ -203,6 +207,10 @@
 	el2_mpam_regs_t mpam;
 #endif
 
+#if ENABLE_FEAT_SCTLR2
+	el2_sctlr2_regs_t sctlr2;
+#endif
+
 } el2_sysregs_t;
 
 /*
@@ -358,6 +366,15 @@
 #define write_el2_ctx_mpam(ctx, reg, val)
 #endif /* CTX_INCLUDE_MPAM_REGS */
 
+#if ENABLE_FEAT_SCTLR2
+#define read_el2_ctx_sctlr2(ctx, reg)		(((ctx)->sctlr2).reg)
+#define write_el2_ctx_sctlr2(ctx, reg, val)	((((ctx)->sctlr2).reg)	\
+							= (uint64_t) (val))
+#else
+#define read_el2_ctx_sctlr2(ctx, reg)		ULL(0)
+#define write_el2_ctx_sctlr2(ctx, reg, val)
+#endif /* ENABLE_FEAT_SCTLR2 */
+
 /******************************************************************************/
 
 #endif /* __ASSEMBLER__ */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index ae5aa23..118b537 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -15,6 +15,7 @@
 #endif
 #if ENABLE_RME
 #include <services/rmm_core_manifest.h>
+#include <services/rmm_el3_token_sign.h>
 #endif
 #include <drivers/fwu/fwu_metadata.h>
 #if TRNG_SUPPORT
@@ -376,6 +377,15 @@
 				   uint64_t *remaining_len);
 int plat_rmmd_get_cca_realm_attest_key(uintptr_t buf, size_t *len,
 				       unsigned int type);
+/* The following 3 functions are to be implement if
+ * RMMD_ENABLE_EL3_TOKEN_SIGN=1.
+ * The following three functions are expected to return E_RMM_* error codes.
+ */
+int plat_rmmd_el3_token_sign_get_rak_pub(uintptr_t buf, size_t *len,
+					   unsigned int type);
+int plat_rmmd_el3_token_sign_push_req(
+				const struct el3_token_sign_request *req);
+int plat_rmmd_el3_token_sign_pull_resp(struct el3_token_sign_response *resp);
 size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared);
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest);
 #endif
diff --git a/include/services/rmm_el3_token_sign.h b/include/services/rmm_el3_token_sign.h
new file mode 100644
index 0000000..154940c
--- /dev/null
+++ b/include/services/rmm_el3_token_sign.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2024, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMM_EL3_TOKEN_SIGN_H
+#define RMM_EL3_TOKEN_SIGN_H
+
+#include <stdint.h>
+#include <lib/cassert.h>
+#include <services/rmmd_svc.h>
+
+/*
+ * Defines member of structure and reserves space
+ * for the next member with specified offset.
+ */
+/* cppcheck-suppress [misra-c2012-20.7] */
+#define SET_MEMBER(member, start, end)	\
+	union {				\
+		member;			\
+		unsigned char reserved##end[((end) - (start))];	\
+	}
+
+#define EL3_TOKEN_RESPONSE_MAX_SIG_LEN U(512)
+
+struct el3_token_sign_request {
+	SET_MEMBER(uint32_t sig_alg_id, 0x0, 0x8);
+	SET_MEMBER(uint64_t rec_granule, 0x8, 0x10);
+	SET_MEMBER(uint64_t req_ticket, 0x10, 0x18);
+	SET_MEMBER(uint32_t hash_alg_id, 0x18, 0x20);
+	SET_MEMBER(uint8_t hash_buf[SHA512_DIGEST_SIZE], 0x20, 0x60);
+};
+
+CASSERT(__builtin_offsetof(struct el3_token_sign_request, sig_alg_id) == 0x0U,
+	assert_el3_token_sign_request_sig_alg_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_request, rec_granule) == 0x8U,
+	assert_el3_token_sign_request_rec_granule_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_request, req_ticket) == 0x10U,
+	assert_el3_token_sign_request_req_ticket_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_request, hash_alg_id) == 0x18U,
+	assert_el3_token_sign_request_hash_alg_id_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_request, hash_buf) == 0x20U,
+	assert_el3_token_sign_request_hash_buf_mismatch);
+
+
+struct el3_token_sign_response {
+	SET_MEMBER(uint64_t rec_granule, 0x0, 0x8);
+	SET_MEMBER(uint64_t req_ticket, 0x8, 0x10);
+	SET_MEMBER(uint16_t sig_len, 0x10, 0x12);
+	SET_MEMBER(uint8_t signature_buf[EL3_TOKEN_RESPONSE_MAX_SIG_LEN], 0x12, 0x212);
+};
+
+CASSERT(__builtin_offsetof(struct el3_token_sign_response, rec_granule) == 0x0U,
+	assert_el3_token_sign_resp_rec_granule_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_response, req_ticket) == 0x8U,
+	assert_el3_token_sign_resp_req_ticket_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_response, sig_len) == 0x10U,
+	assert_el3_token_sign_resp_sig_len_mismatch);
+CASSERT(__builtin_offsetof(struct el3_token_sign_response, signature_buf) == 0x12U,
+	assert_el3_token_sign_resp_sig_buf_mismatch);
+
+#endif /* RMM_EL3_TOKEN_SIGN_H */
diff --git a/include/services/rmmd_svc.h b/include/services/rmmd_svc.h
index 635c28e..0cc8628 100644
--- a/include/services/rmmd_svc.h
+++ b/include/services/rmmd_svc.h
@@ -129,8 +129,43 @@
 					/* 0x1B3 */
 #define RMM_ATTEST_GET_PLAT_TOKEN	SMC64_RMMD_EL3_FID(U(3))
 
+/* Starting RMM-EL3 interface version 0.4 */
+#define RMM_EL3_FEATURES				SMC64_RMMD_EL3_FID(U(4))
+#define RMM_EL3_FEAT_REG_0_IDX				U(0)
+/* Bit 0 of FEAT_REG_0 */
+/* 1 - the feature is present in EL3 , 0 - the feature is absent */
+#define RMM_EL3_FEAT_REG_0_EL3_TOKEN_SIGN_MASK		U(0x1)
+
+/*
+ * Function codes to support attestation where EL3 is used to sign
+ * realm attestation tokens. In this model, the private key is not
+ * exposed to the RMM.
+ * The arguments to this SMC are:
+ *     arg0 - Function ID.
+ *     arg1 - Opcode, one of:
+ *               RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP,
+ *               RMM_EL3_TOKEN_SIGN_PULL_RESP_OP,
+ *               RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP
+ *     arg2 - Pointer to buffer with request/response structures,
+ *            which is in the RMM<->EL3 shared buffer.
+ *     arg3 - Buffer size of memory pointed by arg2.
+ *     arg4 - ECC Curve, when opcode is RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP
+ * The return arguments are:
+ *     ret0 - Status/Error
+ *     ret1 - Size of public key if opcode is RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP
+ */
+#define RMM_EL3_TOKEN_SIGN			SMC64_RMMD_EL3_FID(U(5))
+
+/* Opcodes for RMM_EL3_TOKEN_SIGN  */
+#define RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP          U(1)
+#define RMM_EL3_TOKEN_SIGN_PULL_RESP_OP         U(2)
+#define RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP       U(3)
+
 /* ECC Curve types for attest key generation */
-#define ATTEST_KEY_CURVE_ECC_SECP384R1		0
+#define ATTEST_KEY_CURVE_ECC_SECP384R1		U(0)
+
+/* Identifier for the hash algorithm used for attestation signing */
+#define EL3_TOKEN_SIGN_HASH_ALG_SHA384		U(1)
 
 /*
  * RMM_BOOT_COMPLETE originates on RMM when the boot finishes (either cold
@@ -153,7 +188,7 @@
  * Increase this when a bug is fixed, or a feature is added without
  * breaking compatibility.
  */
-#define RMM_EL3_IFC_VERSION_MINOR	(U(3))
+#define RMM_EL3_IFC_VERSION_MINOR	(U(4))
 
 #define RMM_EL3_INTERFACE_VERSION				\
 	(((RMM_EL3_IFC_VERSION_MAJOR << 16) & 0x7FFFF) |	\
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 6210356..7c84e0e 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -260,6 +260,21 @@
 	 */
 	scr_el3 |= get_scr_el3_from_routing_model(NON_SECURE);
 #endif
+
+	if (is_feat_the_supported()) {
+		/* Set the RCWMASKEn bit in SCR_EL3 to enable access to
+		 * RCWMASK_EL1 and RCWSMASK_EL1 registers.
+		 */
+		scr_el3 |= SCR_RCWMASKEn_BIT;
+	}
+
+	if (is_feat_sctlr2_supported()) {
+		/* Set the SCTLR2En bit in SCR_EL3 to enable access to
+		 * SCTLR2_ELx registers.
+		 */
+		scr_el3 |= SCR_SCTLR2En_BIT;
+	}
+
 	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
 
 	/* Initialize EL2 context registers */
@@ -1437,6 +1452,10 @@
 		write_el2_ctx_gcs(el2_sysregs_ctx, gcscr_el2, read_gcscr_el2());
 		write_el2_ctx_gcs(el2_sysregs_ctx, gcspr_el2, read_gcspr_el2());
 	}
+
+	if (is_feat_sctlr2_supported()) {
+		write_el2_ctx_sctlr2(el2_sysregs_ctx, sctlr2_el2, read_sctlr2_el2());
+	}
 }
 
 /*******************************************************************************
@@ -1524,6 +1543,10 @@
 		write_gcscr_el2(read_el2_ctx_gcs(el2_sysregs_ctx, gcscr_el2));
 		write_gcspr_el2(read_el2_ctx_gcs(el2_sysregs_ctx, gcspr_el2));
 	}
+
+	if (is_feat_sctlr2_supported()) {
+		write_sctlr2_el2(read_el2_ctx_sctlr2(el2_sysregs_ctx, sctlr2_el2));
+	}
 }
 #endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
 
@@ -1712,6 +1735,16 @@
 		write_el1_ctx_gcs(ctx, gcspr_el1, read_gcspr_el1());
 		write_el1_ctx_gcs(ctx, gcspr_el0, read_gcspr_el0());
 	}
+
+	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());
+	}
+
+	if (is_feat_sctlr2_supported()) {
+		write_el1_ctx_sctlr2(ctx, sctlr2_el1, read_sctlr2_el1());
+	}
+
 }
 
 static void el1_sysregs_context_restore(el1_sysregs_t *ctx)
@@ -1807,6 +1840,16 @@
 		write_gcspr_el1(read_el1_ctx_gcs(ctx, gcspr_el1));
 		write_gcspr_el0(read_el1_ctx_gcs(ctx, gcspr_el0));
 	}
+
+	if (is_feat_the_supported()) {
+		write_rcwmask_el1(read_el1_ctx_the(ctx, rcwmask_el1));
+		write_rcwsmask_el1(read_el1_ctx_the(ctx, rcwsmask_el1));
+	}
+
+	if (is_feat_sctlr2_supported()) {
+		write_sctlr2_el1(read_el1_ctx_sctlr2(ctx, sctlr2_el1));
+	}
+
 }
 
 /*******************************************************************************
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
index 675779f..9533e98 100644
--- a/make_helpers/arch_features.mk
+++ b/make_helpers/arch_features.mk
@@ -90,7 +90,7 @@
 
 # Enable the features which are mandatory from ARCH version 8.9 and upwards.
 ifeq "8.9" "$(word 1, $(sort 8.9 $(ARM_ARCH_MAJOR).$(ARM_ARCH_MINOR)))"
-armv8-9-a-feats         := ENABLE_FEAT_TCR2 ENABLE_FEAT_DEBUGV8P9
+armv8-9-a-feats         := ENABLE_FEAT_TCR2 ENABLE_FEAT_DEBUGV8P9 ENABLE_FEAT_SCTLR2
 # 8.8 Compliant
 armv8-9-a-feats         += ${armv8-8-a-feats}
 FEAT_LIST               := ${armv8-9-a-feats}
@@ -219,6 +219,9 @@
 # Flag to enable access to TCR2 (FEAT_TCR2).
 ENABLE_FEAT_TCR2		?=	0
 
+# Flag to enable access to SCTLR2 (FEAT_SCTLR2).
+ENABLE_FEAT_SCTLR2		?=	0
+
 #
 ################################################################################
 # Optional Features defaulted to 0 or 2, if they are not enabled from
@@ -341,6 +344,13 @@
 ENABLE_FEAT_FGT2			?=	0
 
 #----
+# 8.8
+#----
+
+# Flag to enable FEAT_THE (Translation Hardening Extension)
+ENABLE_FEAT_THE				?=	0
+
+#----
 # 8.9
 #----
 
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 8c884b4..584542c 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -409,3 +409,6 @@
 # Allow platforms to save/restore DSU PMU registers over a power cycle.
 # Disabled by default and must be enabled by individual platforms.
 PRESERVE_DSU_PMU_REGS		:= 0
+
+# Enable RMMD to forward attestation requests from RMM to EL3.
+RMMD_ENABLE_EL3_TOKEN_SIGN	:= 0
diff --git a/plat/amd/versal2/bl31_setup.c b/plat/amd/versal2/bl31_setup.c
index 970fca9..6c8cf5a 100644
--- a/plat/amd/versal2/bl31_setup.c
+++ b/plat/amd/versal2/bl31_setup.c
@@ -20,6 +20,7 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 #include <plat_arm.h>
+#include <plat_console.h>
 #include <scmi.h>
 
 #include <def.h>
@@ -79,7 +80,6 @@
 	(void)arg2;
 	(void)arg3;
 	uint32_t uart_clock;
-	int32_t rc;
 
 	board_detection();
 
@@ -125,30 +125,7 @@
 
 	uart_clock = get_uart_clk();
 
-	if (CONSOLE_IS(pl011_0) || CONSOLE_IS(pl011_1)) {
-		static console_t _runtime_console;
-
-		/* Initialize the console to provide early debug support */
-		rc = console_pl011_register(UART_BASE, uart_clock,
-					    UART_BAUDRATE,
-					    &_runtime_console);
-		if (rc == 0) {
-			panic();
-		}
-
-		console_set_scope(&_runtime_console, CONSOLE_FLAG_BOOT |
-				  CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
-	} else if (CONSOLE_IS(dcc)) {
-		/* Initialize the dcc console for debug.
-		 * dcc is over jtag and does not configures uart0 or uart1.
-		 */
-		rc = console_dcc_register();
-		if (rc == 0) {
-			panic();
-		}
-	} else {
-		/* Making MISRA C 2012 15.7 compliant */
-	}
+	setup_console();
 
 	NOTICE("TF-A running on %s %d.%d\n", board_name_decode(),
 	       platform_version / 10U, platform_version % 10U);
@@ -254,6 +231,8 @@
 	if (rc != 0) {
 		panic();
 	}
+
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
 }
 
 /*
diff --git a/plat/amd/versal2/include/def.h b/plat/amd/versal2/include/def.h
index 67244a4..f3a7907 100644
--- a/plat/amd/versal2/include/def.h
+++ b/plat/amd/versal2/include/def.h
@@ -15,12 +15,23 @@
 #define MAX_INTR_EL3			2
 
 /* List all consoles */
-#define CONSOLE_ID_pl011	U(1)
-#define CONSOLE_ID_pl011_0	U(1)
-#define CONSOLE_ID_pl011_1	U(2)
-#define CONSOLE_ID_dcc	U(3)
+#define VERSAL2_CONSOLE_ID_none		0
+#define VERSAL2_CONSOLE_ID_pl011	1
+#define VERSAL2_CONSOLE_ID_pl011_0       1
+#define VERSAL2_CONSOLE_ID_pl011_1       2
+#define VERSAL2_CONSOLE_ID_dcc           3
+#define VERSAL2_CONSOLE_ID_dtb           4
 
-#define CONSOLE_IS(con)	(CONSOLE_ID_ ## con == CONSOLE)
+#define CONSOLE_IS(con) (VERSAL2_CONSOLE_ID_ ## con == VERSAL2_CONSOLE)
+
+/* Runtime console */
+#define RT_CONSOLE_ID_pl011   1
+#define RT_CONSOLE_ID_pl011_0   1
+#define RT_CONSOLE_ID_pl011_1   2
+#define RT_CONSOLE_ID_dcc       3
+#define RT_CONSOLE_ID_dtb       4
+
+#define RT_CONSOLE_IS(con)      (RT_CONSOLE_ID_ ## con == CONSOLE_RUNTIME)
 
 /* List all platforms */
 #define SILICON		U(0)
@@ -143,11 +154,35 @@
 
 #define UART_BAUDRATE	115200
 
-#if CONSOLE_IS(pl011_1)
-#define UART_BASE		UART1_BASE
+#if CONSOLE_IS(pl011) || CONSOLE_IS(dtb)
+#define UART_BASE	    UART0_BASE
+# define UART_TYPE	CONSOLE_PL011
+#elif CONSOLE_IS(pl011_1)
+#define UART_BASE           UART1_BASE
+# define UART_TYPE	CONSOLE_PL011
+#elif CONSOLE_IS(dcc)
+# define UART_BASE	0x0
+# define UART_TYPE	CONSOLE_DCC
+#elif CONSOLE_IS(none)
+# define UART_TYPE	CONSOLE_NONE
+#else
+# error "invalid VERSAL2_CONSOLE"
+#endif
+
+/* Runtime console */
+#if defined(CONSOLE_RUNTIME)
+#if RT_CONSOLE_IS(pl011) || RT_CONSOLE_IS(dtb)
+# define RT_UART_BASE UART0_BASE
+# define RT_UART_TYPE	CONSOLE_PL011
+#elif RT_CONSOLE_IS(pl011_1)
+# define RT_UART_BASE UART1_BASE
+# define RT_UART_TYPE	CONSOLE_PL011
+#elif RT_CONSOLE_IS(dcc)
+# define RT_UART_BASE	0x0
+# define RT_UART_TYPE	CONSOLE_DCC
 #else
-/* Default console is UART0 */
-#define UART_BASE            UART0_BASE
+# error "invalid CONSOLE_RUNTIME"
+#endif
 #endif
 
 #endif /* DEF_H */
diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk
index 3892fcb..e2112e0 100644
--- a/plat/amd/versal2/platform.mk
+++ b/plat/amd/versal2/platform.mk
@@ -57,13 +57,28 @@
 USE_COHERENT_MEM := 0
 HW_ASSISTED_COHERENCY := 1
 
-CONSOLE	?=	pl011
-ifeq (${CONSOLE}, $(filter ${CONSOLE},pl011 pl011_0 pl011_1 dcc))
+VERSAL2_CONSOLE  ?=      pl011
+ifeq (${VERSAL2_CONSOLE}, $(filter ${VERSAL2_CONSOLE},pl011 pl011_0 pl011_1 dcc dtb none))
+	else
+	  $(error "Please define VERSAL2_CONSOLE")
+  endif
+
+$(eval $(call add_define_val,VERSAL2_CONSOLE,VERSAL2_CONSOLE_ID_${VERSAL2_CONSOLE}))
+
+# Runtime console in default console in DEBUG build
+ifeq ($(DEBUG), 1)
+CONSOLE_RUNTIME ?= pl011
+endif
+
+# Runtime console
+ifdef CONSOLE_RUNTIME
+ifeq 	(${CONSOLE_RUNTIME}, $(filter ${CONSOLE_RUNTIME},pl011 pl011_0 pl011_1 dcc dtb))
+$(eval $(call add_define_val,CONSOLE_RUNTIME,RT_CONSOLE_ID_${CONSOLE_RUNTIME}))
 else
-  $(error Please define CONSOLE)
+	$(error "Please define CONSOLE_RUNTIME")
+endif
 endif
 
-$(eval $(call add_define_val,CONSOLE,CONSOLE_ID_${CONSOLE}))
 
 ifdef XILINX_OF_BOARD_DTB_ADDR
 $(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
@@ -109,6 +124,9 @@
 BL31_SOURCES		+=	${PLAT_PATH}/plat_psci.c
 
 BL31_SOURCES		+=	plat/xilinx/common/plat_fdt.c			\
+				common/fdt_wrappers.c                           \
+				plat/xilinx/common/plat_fdt.c                   \
+				plat/xilinx/common/plat_console.c               \
 				plat/xilinx/common/plat_startup.c		\
 				plat/xilinx/common/ipi.c			\
 				plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c	\
diff --git a/plat/amd/versal2/scmi.c b/plat/amd/versal2/scmi.c
index 7f4b6df..59aff08 100644
--- a/plat/amd/versal2/scmi.c
+++ b/plat/amd/versal2/scmi.c
@@ -51,8 +51,8 @@
 	CLOCK_CELL(CLK_SERIAL1_0, CLK_SERIAL1_0, "uart1_uartclk", true, 100000000),
 	CLOCK_CELL(CLK_SERIAL1_1, CLK_SERIAL1_1, "uart1_apb_pclk", true, 100000000),
 	CLOCK_CELL(CLK_UFS0_0, CLK_UFS0_0, "ufs_core_clk", true, 100000000),
-	CLOCK_CELL(CLK_UFS0_1, CLK_UFS0_1, "ufs_phy_clk", true, 100000000),
-	CLOCK_CELL(CLK_UFS0_2, CLK_UFS0_2, "ufs_ref_pclk", true, 100000000),
+	CLOCK_CELL(CLK_UFS0_1, CLK_UFS0_1, "ufs_phy_clk", true, 26000000),
+	CLOCK_CELL(CLK_UFS0_2, CLK_UFS0_2, "ufs_ref_pclk", true, 26000000),
 	CLOCK_CELL(CLK_USB0_0, CLK_USB0_0, "usb0_bus_clk", true, 100000000),
 	CLOCK_CELL(CLK_USB0_1, CLK_USB0_1, "usb0_ref_clk", true, 100000000),
 	CLOCK_CELL(CLK_USB0_2, CLK_USB0_2, "usb0_dwc_clk", true, 100000000),
@@ -649,6 +649,11 @@
 			/* Keep i2c on 100MHz to calculate rates properly */
 			if (i >= CLK_I2C0_0 && i <= CLK_I2C7_0)
 				continue;
+
+			/* Keep UFS clocks to default values to get the expected rates */
+			if (i >= CLK_UFS0_0 && i <= CLK_UFS0_2)
+				continue;
+
 			/*
 			 * SPP supports multiple versions.
 			 * The cpu_clock value is set to corresponding SPP
diff --git a/plat/arm/board/fvp/fvp_el3_token_sign.c b/plat/arm/board/fvp/fvp_el3_token_sign.c
new file mode 100644
index 0000000..282f94a
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_el3_token_sign.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2024, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <plat/common/platform.h>
+#include <services/rmm_el3_token_sign.h>
+
+static struct el3_token_sign_request el3_req = { 0 };
+static bool el3_req_valid;
+
+/*
+ * According to https://www.secg.org/sec1-v2.pdf 2.3.3
+ * the size of the ECDSA P384 public key is 97 bytes,
+ * with the first byte being 0x04.
+ */
+static uint8_t sample_attest_pub_key[] = {
+	0x04, 0x76, 0xf9, 0x88, 0x09, 0x1b, 0xe5, 0x85, 0xed, 0x41,
+	0x80, 0x1a, 0xec, 0xfa, 0xb8, 0x58, 0x54, 0x8c, 0x63, 0x05,
+	0x7e, 0x16, 0xb0, 0xe6, 0x76, 0x12, 0x0b, 0xbd, 0x0d, 0x2f,
+	0x9c, 0x29, 0xe0, 0x56, 0xc5, 0xd4, 0x1a, 0x01, 0x30, 0xeb,
+	0x9c, 0x21, 0x51, 0x78, 0x99, 0xdc, 0x23, 0x14, 0x6b, 0x28,
+	0xe1, 0xb0, 0x62, 0xbd, 0x3e, 0xa4, 0xb3, 0x15, 0xfd, 0x21,
+	0x9f, 0x1c, 0xbb, 0x52, 0x8c, 0xb6, 0xe7, 0x4c, 0xa4, 0x9b,
+	0xe1, 0x67, 0x73, 0x73, 0x4f, 0x61, 0xa1, 0xca, 0x61, 0x03,
+	0x1b, 0x2b, 0xbf, 0x3d, 0x91, 0x8f, 0x2f, 0x94, 0xff, 0xc4,
+	0x22, 0x8e, 0x50, 0x91, 0x95, 0x44, 0xae
+};
+
+/*
+ * FVP does not support HES, so provide 0's as keys.
+ */
+int plat_rmmd_el3_token_sign_get_rak_pub(uintptr_t buf, size_t *len,
+					 unsigned int type)
+{
+	(void)type;
+	if (*len < sizeof(sample_attest_pub_key)) {
+		return E_RMM_INVAL;
+	}
+
+	if (type != ATTEST_KEY_CURVE_ECC_SECP384R1) {
+		ERROR("Invalid ECC curve specified\n");
+		return E_RMM_INVAL;
+	}
+
+	*len = sizeof(sample_attest_pub_key);
+
+	(void)memcpy((void *)buf, sample_attest_pub_key,
+		     sizeof(sample_attest_pub_key));
+
+	return 0;
+}
+
+int plat_rmmd_el3_token_sign_push_req(const struct el3_token_sign_request *req)
+{
+	/*
+	 * TODO: Today this function is called with a lock held on the
+	 * RMM<->EL3 shared buffer. In the future, we may move to a
+	 * different design that may require handling multi-threaded
+	 * calls to this function, for example, if we have a per CPU
+	 * buffer between RMM and EL3.
+	 */
+	if (el3_req_valid) {
+		return E_RMM_AGAIN;
+	}
+
+	el3_req = *req;
+
+	if ((el3_req.hash_alg_id != EL3_TOKEN_SIGN_HASH_ALG_SHA384) ||
+	    (el3_req.sig_alg_id != ATTEST_KEY_CURVE_ECC_SECP384R1)) {
+		return E_RMM_INVAL;
+	}
+
+	el3_req_valid = true;
+
+	return 0;
+}
+
+int plat_rmmd_el3_token_sign_pull_resp(struct el3_token_sign_response *resp)
+{
+	if (!el3_req_valid) {
+		return E_RMM_AGAIN;
+	}
+
+	resp->rec_granule = el3_req.rec_granule;
+	resp->req_ticket = el3_req.req_ticket;
+	resp->sig_len = (uint16_t)sizeof(resp->signature_buf);
+	/* TODO: Provide real signature */
+	memset(resp->signature_buf, 0, sizeof(resp->signature_buf));
+
+	el3_req_valid = false;
+
+	return 0;
+}
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index feae802..33e1feb 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -71,11 +71,13 @@
 ENABLE_FEAT_ECV			:= 2
 ENABLE_FEAT_FGT			:= 2
 ENABLE_FEAT_FGT2		:= 2
+ENABLE_FEAT_THE			:= 2
 ENABLE_FEAT_TCR2		:= 2
 ENABLE_FEAT_S2PIE		:= 2
 ENABLE_FEAT_S1PIE		:= 2
 ENABLE_FEAT_S2POE		:= 2
 ENABLE_FEAT_S1POE		:= 2
+ENABLE_FEAT_SCTLR2		:= 2
 ENABLE_FEAT_MTE2		:= 2
 
 # The FVP platform depends on this macro to build with correct GIC driver.
@@ -264,7 +266,8 @@
 				plat/arm/board/fvp/fvp_cpu_pwr.c
 
 BL31_SOURCES		+=	plat/arm/board/fvp/fvp_plat_attest_token.c	\
-				plat/arm/board/fvp/fvp_realm_attest_key.c
+				plat/arm/board/fvp/fvp_realm_attest_key.c	\
+				plat/arm/board/fvp/fvp_el3_token_sign.c
 endif
 
 ifeq (${ENABLE_FEAT_RNG_TRAP},1)
diff --git a/plat/intel/soc/agilex/bl2_plat_setup.c b/plat/intel/soc/agilex/bl2_plat_setup.c
index 36820b2..084539e 100644
--- a/plat/intel/soc/agilex/bl2_plat_setup.c
+++ b/plat/intel/soc/agilex/bl2_plat_setup.c
@@ -129,11 +129,13 @@
 
 	switch (boot_source) {
 	case BOOT_SOURCE_SDMMC:
+		NOTICE("SDMMC boot\n");
 		dw_mmc_init(&params, &mmc_info);
 		socfpga_io_setup(boot_source, PLAT_SDMMC_DATA_BASE);
 		break;
 
 	case BOOT_SOURCE_QSPI:
+		NOTICE("QSPI boot\n");
 		cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL,
 			QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS,
 			QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0);
diff --git a/plat/intel/soc/agilex/include/agilex_memory_controller.h b/plat/intel/soc/agilex/include/agilex_memory_controller.h
index 9db4292..f0bbeea 100644
--- a/plat/intel/soc/agilex/include/agilex_memory_controller.h
+++ b/plat/intel/soc/agilex/include/agilex_memory_controller.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,7 +28,7 @@
 #define AGX_MPFE_HMC_ADP_ECCCTRL1			0xf8011100
 #define AGX_MPFE_HMC_ADP_ECCCTRL2			0xf8011104
 #define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT		0xf8011218
-#define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE	0x000000ff
+#define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE	0x0000000f
 #define AGX_MPFE_HMC_ADP_RSTHANDSHAKECTRL		0xf8011214
 
 
diff --git a/plat/intel/soc/agilex/include/socfpga_plat_def.h b/plat/intel/soc/agilex/include/socfpga_plat_def.h
index 9ef7598..4e3397f 100644
--- a/plat/intel/soc/agilex/include/socfpga_plat_def.h
+++ b/plat/intel/soc/agilex/include/socfpga_plat_def.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,6 +19,7 @@
 #define PLAT_PRIMARY_CPU			0
 #define PLAT_CLUSTER_ID_MPIDR_AFF_SHIFT		MPIDR_AFF1_SHIFT
 #define PLAT_CPU_ID_MPIDR_AFF_SHIFT		MPIDR_AFF0_SHIFT
+#define PLAT_TIMER_BASE_ADDR			0xFFD01000
 
 /* FPGA config helpers */
 #define INTEL_SIP_SMC_FPGA_CONFIG_ADDR		0x400000
diff --git a/plat/intel/soc/agilex5/bl2_plat_setup.c b/plat/intel/soc/agilex5/bl2_plat_setup.c
index 265ee57..b75c78c 100644
--- a/plat/intel/soc/agilex5/bl2_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl2_plat_setup.c
@@ -20,9 +20,11 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
 #include "agilex5_clock_manager.h"
+#include "agilex5_ddr.h"
 #include "agilex5_memory_controller.h"
 #include "agilex5_mmc.h"
 #include "agilex5_pinmux.h"
+#include "agilex5_power_manager.h"
 #include "agilex5_system_manager.h"
 #include "ccu/ncore_ccu.h"
 #include "combophy/combophy.h"
@@ -70,29 +72,50 @@
 				u_register_t x2, u_register_t x4)
 {
 	static console_t console;
+	handoff reverse_handoff_ptr;
 
-	handoff reverse_handoff_ptr = { 0 };
+	/* Enable nonsecure access for peripherals and other misc components */
+	enable_nonsecure_access();
+
+	/* Bring all the required peripherals out of reset */
+	deassert_peripheral_reset();
+
+	/*
+	 * Initialize the UART console early in BL2 EL3 boot flow to get
+	 * the error/notice messages wherever required.
+	 */
+	console_16550_register(PLAT_INTEL_UART_BASE, PLAT_UART_CLOCK,
+			       PLAT_BAUDRATE, &console);
 
+	/* Generic delay timer init */
 	generic_delay_timer_init();
+
+	socfpga_delay_timer_init();
+
+	/* Get the handoff data */
+	if ((socfpga_get_handoff(&reverse_handoff_ptr)) != 0) {
+		ERROR("BL2: Failed to get the correct handoff data\n");
+		panic();
+	}
+
 	config_clkmgr_handoff(&reverse_handoff_ptr);
+	/* Configure power manager PSS SRAM power gate */
+	config_pwrmgr_handoff(&reverse_handoff_ptr);
+
+	/* Initialize the mailbox to enable communication between HPS and SDM */
 	mailbox_init();
-	enable_nonsecure_access();
 
-	deassert_peripheral_reset();
+	/* DDR and IOSSM driver init */
+	agilex5_ddr_init(&reverse_handoff_ptr);
+
 	if (combo_phy_init(&reverse_handoff_ptr) != 0) {
 		ERROR("Combo Phy initialization failed\n");
 	}
 
-	console_16550_register(PLAT_INTEL_UART_BASE, PLAT_UART_CLOCK,
-	PLAT_BAUDRATE, &console);
-
-	/* Store magic number */
-	// TODO: Temp workaround to ungate testing
-	// mmio_write_32(L2_RESET_DONE_REG, PLAT_L2_RESET_REQ);
-
+	/* Enable FPGA bridges as required */
 	if (!intel_mailbox_is_fpga_not_ready()) {
 		socfpga_bridges_enable(SOC2FPGA_MASK | LWHPS2FPGA_MASK |
-					FPGA2SOC_MASK | F2SDRAM0_MASK);
+				       FPGA2SOC_MASK | F2SDRAM0_MASK);
 	}
 }
 
diff --git a/plat/intel/soc/agilex5/bl31_plat_setup.c b/plat/intel/soc/agilex5/bl31_plat_setup.c
index 96c4161..b6fc93e 100644
--- a/plat/intel/soc/agilex5/bl31_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl31_plat_setup.c
@@ -58,9 +58,8 @@
 	mmio_write_64(PLAT_SEC_ENTRY, PLAT_SEC_WARM_ENTRY);
 
 	console_16550_register(PLAT_INTEL_UART_BASE, PLAT_UART_CLOCK,
-	PLAT_BAUDRATE, &console);
+			       PLAT_BAUDRATE, &console);
 
-	init_ncore_ccu();
 	setup_smmu_stream_id();
 
 	/*
@@ -191,8 +190,8 @@
 	uint32_t boot_core = 0x00;
 	uint32_t cpuid = 0x00;
 
-	cpuid = read_mpidr();
-	boot_core = (mmio_read_32(AGX5_PWRMGR(MPU_BOOTCONFIG)) & 0xC00);
+	cpuid = MPIDR_AFFLVL1_VAL(read_mpidr());
+	boot_core = ((mmio_read_32(AGX5_PWRMGR(MPU_BOOTCONFIG)) & 0xC00) >> 10);
 	NOTICE("BL31: Boot Core = %x\n", boot_core);
 	NOTICE("BL31: CPU ID = %x\n", cpuid);
 	INFO("BL31: Invalidate Data cache\n");
diff --git a/plat/intel/soc/agilex5/include/agilex5_ddr.h b/plat/intel/soc/agilex5/include/agilex5_ddr.h
new file mode 100644
index 0000000..631e006
--- /dev/null
+++ b/plat/intel/soc/agilex5/include/agilex5_ddr.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGILEX5_DDR_H
+#define AGILEX5_DDR_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <lib/utils_def.h>
+
+#include "socfpga_handoff.h"
+
+#define CONFIG_NR_DRAM_BANKS	1
+
+typedef unsigned long long phys_addr_t;
+typedef unsigned long long phys_size_t;
+typedef phys_addr_t fdt_addr_t;
+
+/* DDR/RAM configuration */
+struct ddr_info {
+	phys_addr_t start;
+	phys_size_t size;
+};
+
+int agilex5_ddr_init(handoff *hoff_ptr);
+
+#endif /* AGILEX5_DDR_H */
diff --git a/plat/intel/soc/agilex5/include/agilex5_iossm_mailbox.h b/plat/intel/soc/agilex5/include/agilex5_iossm_mailbox.h
new file mode 100644
index 0000000..1fd8ef6
--- /dev/null
+++ b/plat/intel/soc/agilex5/include/agilex5_iossm_mailbox.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGILEX5_IOSSM_MAILBOX_H
+#define AGILEX5_IOSSM_MAILBOX_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "lib/mmio.h"
+#include "agilex5_ddr.h"
+
+#define TIMEOUT_5000MS					5000
+#define TIMEOUT						TIMEOUT_5000MS
+#define IOSSM_STATUS_CAL_SUCCESS			BIT(0)
+#define IOSSM_STATUS_CAL_FAIL				BIT(1)
+#define IOSSM_STATUS_CAL_BUSY				BIT(2)
+#define IOSSM_STATUS_COMMAND_RESPONSE_READY		1
+#define IOSSM_CMD_RESPONSE_STATUS_OFFSET		0x45C
+#define IOSSM_CMD_RESPONSE_DATA_0_OFFSET		0x458
+#define IOSSM_CMD_RESPONSE_DATA_1_OFFSET		0x454
+#define IOSSM_CMD_RESPONSE_DATA_2_OFFSET		0x450
+#define IOSSM_CMD_REQ_OFFSET				0x43C
+#define IOSSM_CMD_PARAM_0_OFFSET			0x438
+#define IOSSM_CMD_PARAM_1_OFFSET			0x434
+#define IOSSM_CMD_PARAM_2_OFFSET			0x430
+#define IOSSM_CMD_PARAM_3_OFFSET			0x42C
+#define IOSSM_CMD_PARAM_4_OFFSET			0x428
+#define IOSSM_CMD_PARAM_5_OFFSET			0x424
+#define IOSSM_CMD_PARAM_6_OFFSET			0x420
+#define IOSSM_STATUS_OFFSET				0x400
+#define IOSSM_CMD_RESPONSE_DATA_SHORT_MASK		GENMASK(31, 16)
+#define IOSSM_CMD_RESPONSE_DATA_SHORT(data)		(((data) & \
+							IOSSM_CMD_RESPONSE_DATA_SHORT_MASK) >> 16)
+#define MAX_IO96B_SUPPORTED				2
+#define MAX_MEM_INTERFACES_SUPPORTED			2
+
+/* supported mailbox command type */
+enum iossm_mailbox_cmd_type  {
+	CMD_NOP,
+	CMD_GET_SYS_INFO,
+	CMD_GET_MEM_INFO,
+	CMD_GET_MEM_CAL_INFO,
+	CMD_TRIG_CONTROLLER_OP,
+	CMD_TRIG_MEM_CAL_OP
+};
+
+/* supported mailbox command opcode */
+enum iossm_mailbox_cmd_opcode  {
+	GET_MEM_INTF_INFO = 0x0001,
+	GET_MEM_TECHNOLOGY,
+	GET_MEMCLK_FREQ_KHZ,
+	GET_MEM_WIDTH_INFO,
+	ECC_ENABLE_SET = 0x0101,
+	ECC_ENABLE_STATUS,
+	ECC_INTERRUPT_STATUS,
+	ECC_INTERRUPT_ACK,
+	ECC_INTERRUPT_MASK,
+	ECC_WRITEBACK_ENABLE,
+	ECC_SCRUB_IN_PROGRESS_STATUS = 0x0201,
+	ECC_SCRUB_MODE_0_START,
+	ECC_SCRUB_MODE_1_START,
+	BIST_STANDARD_MODE_START = 0x0301,
+	BIST_RESULTS_STATUS,
+	BIST_MEM_INIT_START,
+	BIST_MEM_INIT_STATUS,
+	BIST_SET_DATA_PATTERN_UPPER,
+	BIST_SET_DATA_PATTERN_LOWER,
+	TRIG_MEM_CAL = 0x000a,
+	GET_MEM_CAL_STATUS
+};
+
+/*
+ * IOSSM mailbox required information
+ *
+ * @num_mem_interface:	Number of memory interfaces instantiated
+ * @ip_type:		IP type implemented on the IO96B
+ * @ip_instance_id:	IP identifier for every IP instance implemented on the IO96B
+ */
+struct io96b_mb_ctrl {
+	uint32_t num_mem_interface;
+	uint32_t ip_type[2];
+	uint32_t ip_instance_id[2];
+};
+
+/*
+ * IOSSM mailbox response outputs
+ *
+ * @cmd_resp_status: Command Interface status
+ * @cmd_resp_data_*: More spaces for command response
+ */
+struct io96b_mb_resp {
+	uint32_t cmd_resp_status;
+	uint32_t cmd_resp_data_0;
+	uint32_t cmd_resp_data_1;
+	uint32_t cmd_resp_data_2;
+};
+
+/*
+ * IO96B instance specific information
+ *
+ * @size:		Memory size
+ * @io96b_csr_addr:	IO96B instance CSR address
+ * @cal_status:		IO96B instance calibration status
+ * @mb_ctrl:		IOSSM mailbox required information
+ */
+struct io96b_instance {
+	uint16_t size;
+	phys_addr_t io96b_csr_addr;
+	bool cal_status;
+	struct io96b_mb_ctrl mb_ctrl;
+};
+
+/*
+ * Overall IO96B instance(s) information
+ *
+ * @num_instance:	Number of instance(s) assigned to HPS
+ * @overall_cal_status: Overall calibration status for all IO96B instance(s)
+ * @ddr_type:		DDR memory type
+ * @ecc_status:		ECC enable status (false = disabled, true = enabled)
+ * @overall_size:	Total DDR memory size
+ * @io96b_0:		IO96B 0 instance specific information
+ * @io96b_1:		IO96B 1 instance specific information
+ */
+struct io96b_info {
+	uint8_t num_instance;
+	bool overall_cal_status;
+	const char *ddr_type;
+	bool ecc_status;
+	uint16_t overall_size;
+	struct io96b_instance io96b_0;
+	struct io96b_instance io96b_1;
+};
+
+int io96b_mb_req(phys_addr_t io96b_csr_addr, uint32_t ip_type, uint32_t instance_id,
+		 uint32_t usr_cmd_type, uint32_t usr_cmd_opcode, uint32_t cmd_param_0,
+		 uint32_t cmd_param_1, uint32_t cmd_param_2, uint32_t cmd_param_3,
+		 uint32_t cmd_param_4, uint32_t cmd_param_5, uint32_t cmd_param_6,
+		 uint32_t resp_data_len, struct io96b_mb_resp *resp);
+
+/* Supported IOSSM mailbox function */
+void io96b_mb_init(struct io96b_info *io96b_ctrl);
+int io96b_cal_status(phys_addr_t addr);
+void init_mem_cal(struct io96b_info *io96b_ctrl);
+int trig_mem_cal(struct io96b_info *io96b_ctrl);
+int get_mem_technology(struct io96b_info *io96b_ctrl);
+int get_mem_width_info(struct io96b_info *io96b_ctrl);
+int ecc_enable_status(struct io96b_info *io96b_ctrl);
+int bist_mem_init_start(struct io96b_info *io96b_ctrl);
+
+#endif /* AGILEX5_IOSSM_MAILBOX_H */
diff --git a/plat/intel/soc/agilex5/include/agilex5_power_manager.h b/plat/intel/soc/agilex5/include/agilex5_power_manager.h
index 1bba74b..178fd5b 100644
--- a/plat/intel/soc/agilex5/include/agilex5_power_manager.h
+++ b/plat/intel/soc/agilex5/include/agilex5_power_manager.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2022-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -77,7 +78,5 @@
 #define AGX5_PWRMGR_PSS_STAT_BUSY_E_BUSY			0x0
 #define AGX5_PWRMGR_PSS_STAT_BUSY(x)				(((x) & 0x000000FF) >> 0)
 
-int pss_sram_power_off(handoff *hoff_ptr);
-int wait_verify_fsm(uint16_t timeout, uint32_t peripheral_handoff);
-
+void config_pwrmgr_handoff(handoff *hoff_ptr);
 #endif
diff --git a/plat/intel/soc/agilex5/include/agilex5_system_manager.h b/plat/intel/soc/agilex5/include/agilex5_system_manager.h
index 53dcd13..75ae78a 100644
--- a/plat/intel/soc/agilex5/include/agilex5_system_manager.h
+++ b/plat/intel/soc/agilex5/include/agilex5_system_manager.h
@@ -25,6 +25,7 @@
 #define SOCFPGA_SYSMGR_TSN_0_ACE					0x50
 #define SOCFPGA_SYSMGR_TSN_1_ACE					0x54
 #define SOCFPGA_SYSMGR_TSN_2_ACE					0x58
+#define SOCFPGA_SYSMGR_FPGA_BRIDGE_CTRL				0x5C
 #define SOCFPGA_SYSMGR_FPGAINTF_EN_1					0x68
 #define SOCFPGA_SYSMGR_FPGAINTF_EN_2					0x6C
 #define SOCFPGA_SYSMGR_FPGAINTF_EN_3					0x70
@@ -189,6 +190,8 @@
 #define SYSMGR_SDMMC_SMPLSEL(x)						(((x) & 0x7) << 4)
 
 #define SYSMGR_F2S_BRIDGE_CTRL_EN					BIT(0)
+#define SYSMGR_SOC_BRIDGE_CTRL_EN					BIT(0)
+#define SYSMGR_LWSOC_BRIDGE_CTRL_EN					BIT(1)
 #define IDLE_DATA_LWSOC2FPGA						BIT(4)
 #define IDLE_DATA_SOC2FPGA						BIT(0)
 #define IDLE_DATA_MASK							(IDLE_DATA_LWSOC2FPGA \
diff --git a/plat/intel/soc/agilex5/include/socfpga_plat_def.h b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
index 9bfc304..5789261 100644
--- a/plat/intel/soc/agilex5/include/socfpga_plat_def.h
+++ b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
@@ -11,6 +11,7 @@
 
 #include "agilex5_memory_controller.h"
 #include "agilex5_system_manager.h"
+
 #include <platform_def.h>
 
 /* Platform Setting */
@@ -23,17 +24,18 @@
 #define PLAT_CLUSTER_ID_MPIDR_AFF_SHIFT				MPIDR_AFF2_SHIFT
 #define PLAT_CPU_ID_MPIDR_AFF_SHIFT				MPIDR_AFF1_SHIFT
 #define PLAT_L2_RESET_REQ					0xB007C0DE
+#define PLAT_TIMER_BASE_ADDR					0x10D01000
 
 /* System Counter */
 /* TODO: Update back to 400MHz.
  * This shall be updated to read from L4 clock instead of hardcoded.
  */
-#define PLAT_SYS_COUNTER_FREQ_IN_TICKS				(400000000)
-#define PLAT_SYS_COUNTER_FREQ_IN_MHZ				(400)
+#define PLAT_SYS_COUNTER_FREQ_IN_TICKS				U(400000000)
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ				U(400)
 
 /* FPGA config helpers */
 #define INTEL_SIP_SMC_FPGA_CONFIG_ADDR				0x80400000
-#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE				0x2000000
+#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE				0x82000000
 
 /* QSPI Setting */
 #define CAD_QSPIDATA_OFST					0x10900000
@@ -88,11 +90,10 @@
 #define GIC_SIZE						(0x00100000)
 
 #define BL2_BASE						(0x00000000)
-#define BL2_LIMIT						(0x0002b000)
+#define BL2_LIMIT						(0x0007E000)
 
 #define BL31_BASE						(0x80000000)
 #define BL31_LIMIT						(0x82000000)
-
 /*******************************************************************************
  * UART related constants
  ******************************************************************************/
diff --git a/plat/intel/soc/agilex5/platform.mk b/plat/intel/soc/agilex5/platform.mk
index 90678e1..4bb90d5 100644
--- a/plat/intel/soc/agilex5/platform.mk
+++ b/plat/intel/soc/agilex5/platform.mk
@@ -58,14 +58,16 @@
 		lib/cpus/aarch64/cortex_a76.S				\
 		plat/intel/soc/agilex5/soc/agilex5_clock_manager.c	\
 		plat/intel/soc/agilex5/soc/agilex5_memory_controller.c	\
-		plat/intel/soc/agilex5/soc/agilex5_mmc.c			\
+		plat/intel/soc/agilex5/soc/agilex5_mmc.c		\
 		plat/intel/soc/agilex5/soc/agilex5_pinmux.c		\
 		plat/intel/soc/agilex5/soc/agilex5_power_manager.c	\
+		plat/intel/soc/agilex5/soc/agilex5_ddr.c		\
+		plat/intel/soc/agilex5/soc/agilex5_iossm_mailbox.c	\
 		plat/intel/soc/common/bl2_plat_mem_params_desc.c	\
 		plat/intel/soc/common/socfpga_image_load.c		\
 		plat/intel/soc/common/socfpga_ros.c			\
 		plat/intel/soc/common/socfpga_storage.c			\
-		plat/intel/soc/common/socfpga_vab.c				\
+		plat/intel/soc/common/socfpga_vab.c			\
 		plat/intel/soc/common/soc/socfpga_emac.c		\
 		plat/intel/soc/common/soc/socfpga_firewall.c		\
 		plat/intel/soc/common/soc/socfpga_handoff.c		\
diff --git a/plat/intel/soc/agilex5/soc/agilex5_ddr.c b/plat/intel/soc/agilex5/soc/agilex5_ddr.c
new file mode 100644
index 0000000..ef2ae57
--- /dev/null
+++ b/plat/intel/soc/agilex5/soc/agilex5_ddr.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include "lib/mmio.h"
+
+#include "agilex5_ddr.h"
+#include "agilex5_iossm_mailbox.h"
+
+/*
+ * TODO: We need to leverage the legacy products DDR drivers and consider
+ * the upcoming products like KM and then come up with common source code/driver
+ * architecture to address all the products in one view.
+ */
+
+#define SYSMGR_BS_COLD3_DDR_RESET_TYPE_MASK		GENMASK(31, 29)
+#define SYSMGR_BS_COLD3_DDR_RESET_TYPE_SHIFT		29
+#define SYSMGR_BS_COLD3_DDR_DBE_MASK			(1 << 1)
+#define SYSMGR_BS_COLD3_OCRAM_DBE_MASK			(1)
+#define SYSMGR_BS_POR0_DDR_PROGRESS_MASK		(1)
+
+/* MPFE NOC registers */
+#define F2SDRAM_SIDEBAND_FLAGOUTSET0			0x50
+#define F2SDRAM_SIDEBAND_FLAGOUTCLR0			0x54
+#define F2SDRAM_SIDEBAND_FLAGOUTSTATUS0			0x58
+
+#define SOCFPGA_F2SDRAM_MGR_ADDRESS			0x18001000
+#define SOCFPGA_MPFE_SCR_IO96B0				0x18000D00
+#define SOCFPGA_MPFE_SCR_IO96B1				0x18000D04
+#define SOCFPGA_MPFE_NOC_SCHED_CSR			0x18000D08
+
+#define SIDEBANDMGR_FLAGOUTSET0_REG			(SOCFPGA_F2SDRAM_MGR_ADDRESS \
+							+ F2SDRAM_SIDEBAND_FLAGOUTSET0)
+#define SIDEBANDMGR_FLAGOUTSTATUS0_REG			(SOCFPGA_F2SDRAM_MGR_ADDRESS \
+							+F2SDRAM_SIDEBAND_FLAGOUTSTATUS0)
+#define SIDEBANDMGR_FLAGOUTCLR0_REG			(SOCFPGA_F2SDRAM_MGR_ADDRESS \
+							+ F2SDRAM_SIDEBAND_FLAGOUTCLR0)
+#define SZ_8						0x00000008
+
+
+/* Firewall MPU DDR SCR registers */
+#define FW_MPU_DDR_SCR_EN				0x00
+#define FW_MPU_DDR_SCR_EN_SET				0x04
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE		0x10
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT		0x14
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT		0x18
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT		0x1c
+
+#define SOCFPGA_FW_DDR_CCU_DMI0_ADDRESS			0x18000800
+#define SOCFPGA_FW_DDR_CCU_DMI1_ADDRESS			0x18000A00
+#define SOCFPGA_FW_TBU2NOC_ADDRESS			0x18000C00
+
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE		0x90
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT	0x94
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT		0x98
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT	0x9c
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT_FIELD	0xff
+
+/* Firewall F2SDRAM DDR SCR registers */
+#define FW_F2SDRAM_DDR_SCR_EN				0x00
+#define FW_F2SDRAM_DDR_SCR_EN_SET			0x04
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE		0x10
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT		0x14
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT		0x18
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT		0x1c
+
+#define FW_MPU_DDR_SCR_WRITEL(data, reg)					\
+	do {									\
+		mmio_write_32(SOCFPGA_FW_DDR_CCU_DMI0_ADDRESS + (reg), data);	\
+		mmio_write_32(SOCFPGA_FW_DDR_CCU_DMI1_ADDRESS + (reg), data);	\
+	} while (0)
+
+#define FW_F2SDRAM_DDR_SCR_WRITEL(data, reg)				\
+	mmio_write_32(SOCFPGA_FW_TBU2NOC_ADDRESS + (reg), data)
+
+/* DDR banks info set */
+static struct ddr_info ddr_info_set[CONFIG_NR_DRAM_BANKS];
+
+/* Reset type */
+enum reset_type {
+	POR_RESET,
+	WARM_RESET,
+	COLD_RESET,
+	NCONFIG,
+	JTAG_CONFIG,
+	RSU_RECONFIG
+};
+
+/* Get reset type by reading boot scratch register cold3 */
+static inline enum reset_type get_reset_type(uint32_t sys_reg)
+{
+	return ((sys_reg & SYSMGR_BS_COLD3_DDR_RESET_TYPE_MASK) >>
+		 SYSMGR_BS_COLD3_DDR_RESET_TYPE_SHIFT);
+}
+
+/* DDR hang check before the reset */
+static inline bool is_ddr_init_hang(void)
+{
+	uint32_t sys_reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0));
+
+	if ((sys_reg & SYSMGR_BS_POR0_DDR_PROGRESS_MASK) != 0) {
+		INFO("DDR: Hang before this reset\n");
+		return true;
+	}
+
+	return false;
+}
+
+/* Set the DDR init progress bit */
+static inline void ddr_init_inprogress(bool start)
+{
+	if (start) {
+		mmio_setbits_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0),
+				SYSMGR_BS_POR0_DDR_PROGRESS_MASK);
+	} else {
+		mmio_clrbits_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_POR_0),
+				SYSMGR_BS_POR0_DDR_PROGRESS_MASK);
+	}
+}
+
+/* Configure the IO96B CSRs address based on the handoff data */
+static void config_io96b_csr_addr(bool is_dualemif, struct io96b_info *io96b_ctrl)
+{
+	if (is_dualemif)
+		io96b_ctrl->num_instance = 2;
+	else
+		io96b_ctrl->num_instance = 1;
+
+	/* Assign IO96B CSR base address if it is valid */
+	for (int i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			io96b_ctrl->io96b_0.io96b_csr_addr = 0x18400000;
+			INFO("DDR: IO96B0 0x%llx CSR enabled\n",
+			     io96b_ctrl->io96b_0.io96b_csr_addr);
+			break;
+
+		case 1:
+			io96b_ctrl->io96b_1.io96b_csr_addr = 0x18800000;
+			INFO("DDR: IO96B1 0x%llx CSR enabled\n",
+			     io96b_ctrl->io96b_1.io96b_csr_addr);
+			break;
+
+		default:
+			ERROR("%s: Invalid IO96B CSR\n", __func__);
+		} /* switch */
+	} /* for */
+}
+
+static inline bool hps_ocram_dbe_status(void)
+{
+	uint32_t sys_reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_3));
+
+	if ((sys_reg & SYSMGR_BS_COLD3_OCRAM_DBE_MASK) != 0)
+		return true;
+
+	return false;
+}
+
+static inline bool ddr_ecc_dbe_status(void)
+{
+	uint32_t sys_reg = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_3));
+
+	if ((sys_reg & SYSMGR_BS_COLD3_DDR_DBE_MASK) != 0)
+		return true;
+
+	return false;
+}
+
+static void sdram_set_firewall_non_f2sdram(void)
+{
+	uint32_t i;
+	phys_size_t value;
+	uint32_t lower, upper;
+
+	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+		if (ddr_info_set[i].size == 0) {
+			continue;
+		}
+
+		value = ddr_info_set[i].start;
+
+		/*
+		 * Keep first 1MB of SDRAM memory region as secure region when
+		 * using ATF flow, where the ATF code is located.
+		 */
+		value += SZ_1M;
+
+		/* Setting non-secure MPU region base and base extended */
+		lower = LO(value);
+		upper = HI(value);
+
+		FW_MPU_DDR_SCR_WRITEL(lower,
+				      FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE +
+				      (i * 4 * sizeof(uint32_t)));
+		FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
+				      FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT +
+				      (i * 4 * sizeof(uint32_t)));
+
+		/* Setting non-secure Non-MPU region base and base extended */
+		FW_MPU_DDR_SCR_WRITEL(lower,
+				      FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE +
+				      (i * 4 * sizeof(uint32_t)));
+		FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
+				      FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT +
+				      (i * 4 * sizeof(uint32_t)));
+
+		/* Setting non-secure MPU limit and limit extended */
+		value = ddr_info_set[i].start + ddr_info_set[i].size - 1;
+
+		lower = LO(value);
+		upper = HI(value);
+
+		FW_MPU_DDR_SCR_WRITEL(lower,
+				      FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT +
+				      (i * 4 * sizeof(uint32_t)));
+		FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
+				      FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT +
+				      (i * 4 * sizeof(uint32_t)));
+
+		/* Setting non-secure Non-MPU limit and limit extended */
+		FW_MPU_DDR_SCR_WRITEL(lower,
+				      FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT +
+				      (i * 4 * sizeof(uint32_t)));
+		FW_MPU_DDR_SCR_WRITEL(upper & 0xff,
+				      FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT +
+				      (i * 4 * sizeof(uint32_t)));
+
+		FW_MPU_DDR_SCR_WRITEL(BIT(i) | BIT(i + 8),
+				      FW_MPU_DDR_SCR_EN_SET);
+	}
+}
+
+static void sdram_set_firewall_f2sdram(void)
+{
+	uint32_t i;
+	phys_size_t value;
+	uint32_t lower, upper;
+
+	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+		if (ddr_info_set[i].size == 0) {
+			continue;
+		}
+
+		value = ddr_info_set[i].start;
+
+		/* Keep first 1MB of SDRAM memory region as secure region when
+		 * using ATF flow, where the ATF code is located.
+		 */
+		value += SZ_1M;
+
+		/* Setting base and base extended */
+		lower = LO(value);
+		upper = HI(value);
+		FW_F2SDRAM_DDR_SCR_WRITEL(lower,
+					  FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE +
+					  (i * 4 * sizeof(uint32_t)));
+		FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff,
+					  FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT +
+					  (i * 4 * sizeof(uint32_t)));
+
+		/* Setting limit and limit extended */
+		value = ddr_info_set[i].start + ddr_info_set[i].size - 1;
+
+		lower = LO(value);
+		upper = HI(value);
+
+		FW_F2SDRAM_DDR_SCR_WRITEL(lower,
+					  FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT +
+					  (i * 4 * sizeof(uint32_t)));
+		FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff,
+					  FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT +
+					  (i * 4 * sizeof(uint32_t)));
+
+		FW_F2SDRAM_DDR_SCR_WRITEL(BIT(i), FW_F2SDRAM_DDR_SCR_EN_SET);
+	}
+}
+
+static void sdram_set_firewall(void)
+{
+	sdram_set_firewall_non_f2sdram();
+	sdram_set_firewall_f2sdram();
+}
+
+/*
+ * Agilex5 DDR/IOSSM controller initialization routine
+ */
+int agilex5_ddr_init(handoff *hoff_ptr)
+{
+	int ret;
+	bool full_mem_init = false;
+	phys_size_t hw_ddr_size;
+	phys_size_t config_ddr_size;
+	struct io96b_info io96b_ctrl;
+	enum reset_type reset_t = get_reset_type(mmio_read_32(SOCFPGA_SYSMGR(
+						BOOT_SCRATCH_COLD_3)));
+	bool is_dualport = hoff_ptr->ddr_config & BIT(0);
+	bool is_dualemif = hoff_ptr->ddr_config & BIT(1);
+
+	NOTICE("DDR: Reset type is '%s'\n",
+	       (reset_t == POR_RESET ? "Power-On" : (reset_t == COLD_RESET ? "Cold" : "Warm")));
+
+	/* DDR initialization progress status tracking */
+	bool is_ddr_hang_bfr_rst = is_ddr_init_hang();
+
+	/* Set the DDR initialization progress */
+	ddr_init_inprogress(true);
+
+	/* Configure the IO96B CSR address based on the handoff data */
+	config_io96b_csr_addr(is_dualemif, &io96b_ctrl);
+
+	/* Configuring MPFE sideband manager registers */
+	/* Dual port setting */
+	if (is_dualport)
+		mmio_setbits_32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(4));
+
+	/* Dual EMIF setting */
+	if (is_dualemif) {
+		/* Set mpfe_lite_active in the system manager */
+		/* TODO: recheck on the bit value?? */
+		mmio_setbits_32(SOCFPGA_SYSMGR(MPFE_CONFIG), BIT(8));
+
+		mmio_setbits_32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(5));
+	}
+
+	if (is_dualport || is_dualemif)
+		INFO("DDR: SIDEBANDMGR_FLAGOUTSTATUS0: 0x%x\n",
+		     mmio_read_32(SIDEBANDMGR_FLAGOUTSTATUS0_REG));
+
+	/* Ensure calibration status passing */
+	init_mem_cal(&io96b_ctrl);
+
+	/* Initiate IOSSM mailbox */
+	io96b_mb_init(&io96b_ctrl);
+
+	/* Need to trigger re-calibration for DDR DBE */
+	if (ddr_ecc_dbe_status()) {
+		io96b_ctrl.io96b_0.cal_status = false;
+		io96b_ctrl.io96b_1.cal_status = false;
+		io96b_ctrl.overall_cal_status = io96b_ctrl.io96b_0.cal_status ||
+						io96b_ctrl.io96b_1.cal_status;
+	}
+
+	/* Trigger re-calibration if calibration failed */
+	if (!(io96b_ctrl.overall_cal_status)) {
+		NOTICE("DDR: Re-calibration in progress...\n");
+		trig_mem_cal(&io96b_ctrl);
+	}
+	NOTICE("DDR: Calibration success\n");
+
+	/* DDR type, DDR size and ECC status) */
+	ret = get_mem_technology(&io96b_ctrl);
+	if (ret != 0) {
+		ERROR("DDR: Failed to get DDR type\n");
+		return ret;
+	}
+
+	ret = get_mem_width_info(&io96b_ctrl);
+	if (ret != 0) {
+		ERROR("DDR: Failed to get DDR size\n");
+		return ret;
+	}
+
+	/* DDR size queried from the IOSSM controller */
+	hw_ddr_size = (phys_size_t)io96b_ctrl.overall_size * SZ_1G / SZ_8;
+
+	/* TODO: Hard code 1GB as of now, and DDR start and end address */
+	config_ddr_size = 0x40000000;
+	ddr_info_set[0].start = 0x80000000;
+	ddr_info_set[0].size = 0x40000000;
+
+	if (config_ddr_size != hw_ddr_size) {
+		WARN("DDR: DDR size configured is (%lld MiB)\n", config_ddr_size >> 20);
+		WARN("DDR: Mismatch with hardware size (%lld MiB).\n", hw_ddr_size >> 20);
+	}
+
+	if (config_ddr_size > hw_ddr_size) {
+		ERROR("DDR: Confgured DDR size is greater than the hardware size - HANG!!!\n");
+		while (1)
+			;
+	}
+
+	ret = ecc_enable_status(&io96b_ctrl);
+	if (ret != 0) {
+		ERROR("DDR: Failed to get DDR ECC status\n");
+		return ret;
+	}
+
+	/*
+	 * HPS cold or warm reset? If yes, skip full memory initialization if
+	 * ECC is enabled to preserve memory content.
+	 */
+	if (io96b_ctrl.ecc_status != 0) {
+		full_mem_init = hps_ocram_dbe_status() | ddr_ecc_dbe_status() |
+				is_ddr_hang_bfr_rst;
+		if ((full_mem_init == true) || (reset_t == WARM_RESET ||
+			reset_t == COLD_RESET) == 0) {
+			ret = bist_mem_init_start(&io96b_ctrl);
+			if (ret != 0) {
+				ERROR("DDR: Failed to fully initialize DDR memory\n");
+				return ret;
+			}
+		}
+		INFO("DDR: ECC initialized successfully\n");
+	}
+
+	sdram_set_firewall();
+
+	/*
+	 * Firewall setting for MPFE CSRs, allow both secure and non-secure
+	 * transactions.
+	 */
+	/* IO96B0_reg */
+	mmio_setbits_32(SOCFPGA_MPFE_SCR_IO96B0, BIT(0));
+	/* IO96B1_reg */
+	mmio_setbits_32(SOCFPGA_MPFE_SCR_IO96B1, BIT(0));
+	/* noc_scheduler_csr */
+	mmio_setbits_32(SOCFPGA_MPFE_NOC_SCHED_CSR, BIT(0));
+
+	INFO("DDR: firewall init done\n");
+
+	/* Ending DDR driver initialization success tracking */
+	ddr_init_inprogress(false);
+
+	NOTICE("###DDR:init success###\n");
+
+	return 0;
+}
diff --git a/plat/intel/soc/agilex5/soc/agilex5_iossm_mailbox.c b/plat/intel/soc/agilex5/soc/agilex5_iossm_mailbox.c
new file mode 100644
index 0000000..c2ab047
--- /dev/null
+++ b/plat/intel/soc/agilex5/soc/agilex5_iossm_mailbox.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include "agilex5_iossm_mailbox.h"
+
+/* supported DDR type list */
+static const char *ddr_type_list[7] = {
+	"DDR4", "DDR5", "DDR5_RDIMM", "LPDDR4", "LPDDR5", "QDRIV", "UNKNOWN"
+};
+
+static inline int wait_for_bit(const void *reg,
+			       const uint32_t mask,
+			       const bool set,
+			       const unsigned int timeout_ms)
+{
+	uint32_t val;
+	uint32_t timeout_sec = (timeout_ms / 1000);
+
+	while (timeout_sec > 0) {
+		val = mmio_read_32((uintptr_t)reg);
+
+		INFO("IOSSM: timeout_sec %d, val %x\n", timeout_sec, val);
+
+		if (!set) {
+			val = ~val;
+		}
+
+		if ((val & mask) == mask) {
+			INFO("IOSSM: %s, success\n", __func__);
+			return 0;
+		}
+
+		/* one second delay */
+		mdelay(1000);
+
+		timeout_sec--;
+	}
+
+	ERROR("IOSSM: %s, failed, time out\n", __func__);
+	return -ETIMEDOUT;
+}
+
+int io96b_mb_req(phys_addr_t io96b_csr_addr, uint32_t ip_type, uint32_t instance_id,
+		 uint32_t usr_cmd_type, uint32_t usr_cmd_opcode, uint32_t cmd_param_0,
+		 uint32_t cmd_param_1, uint32_t cmd_param_2, uint32_t cmd_param_3,
+		 uint32_t cmd_param_4, uint32_t cmd_param_5, uint32_t cmd_param_6,
+		 uint32_t resp_data_len, struct io96b_mb_resp *resp)
+{
+	int i;
+	int ret;
+	uint32_t cmd_req, cmd_resp;
+
+	/* Initialized zeros for responses*/
+	resp->cmd_resp_status = 0;
+	resp->cmd_resp_data_0 = 0;
+	resp->cmd_resp_data_1 = 0;
+	resp->cmd_resp_data_2 = 0;
+
+	/* Ensure CMD_REQ is cleared before write any command request */
+	ret = wait_for_bit((const void *)(io96b_csr_addr + IOSSM_CMD_REQ_OFFSET),
+			   GENMASK(31, 0), 0, 10000);
+
+	if (ret != 0) {
+		ERROR("%s: CMD_REQ not ready\n", __func__);
+		return -1;
+	}
+
+	/* Write CMD_PARAM_* */
+	for (i = 0; i < 6 ; i++) {
+		switch (i) {
+		case 0:
+			if (cmd_param_0 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_0_OFFSET,
+					      cmd_param_0);
+			}
+			break;
+		case 1:
+			if (cmd_param_1 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_1_OFFSET,
+					      cmd_param_1);
+			}
+			break;
+		case 2:
+			if (cmd_param_2 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_2_OFFSET,
+					      cmd_param_2);
+			}
+			break;
+		case 3:
+			if (cmd_param_3 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_3_OFFSET,
+					      cmd_param_3);
+			}
+			break;
+		case 4:
+			if (cmd_param_4 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_4_OFFSET,
+					      cmd_param_4);
+			}
+			break;
+		case 5:
+			if (cmd_param_5 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_5_OFFSET,
+					      cmd_param_5);
+			}
+			break;
+		case 6:
+			if (cmd_param_6 != 0) {
+				mmio_write_32(io96b_csr_addr + IOSSM_CMD_PARAM_6_OFFSET,
+					      cmd_param_6);
+			}
+			break;
+		default:
+			ERROR("IOSSM: %s: Invalid command parameter\n", __func__);
+		}
+	}
+
+	/* Write CMD_REQ (IP_TYPE, IP_INSTANCE_ID, CMD_TYPE and CMD_OPCODE) */
+	cmd_req = (usr_cmd_opcode << 0) | (usr_cmd_type << 16) | (instance_id << 24) |
+		  (ip_type << 29);
+	mmio_write_32(io96b_csr_addr + IOSSM_CMD_REQ_OFFSET, cmd_req);
+	INFO("IOSSM: %s: Write 0x%x to IOSSM_CMD_REQ_OFFSET 0x%llx\n",
+		__func__, cmd_req, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+
+	/* Read CMD_RESPONSE_READY in CMD_RESPONSE_STATUS*/
+	ret = wait_for_bit((const void *)(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET),
+			   IOSSM_STATUS_COMMAND_RESPONSE_READY, 1, 10000);
+
+	if (ret != 0) {
+		ERROR("%s: CMD_RESPONSE ERROR:\n", __func__);
+		cmd_resp = (io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+		ERROR("%s: STATUS_GENERAL_ERROR: 0x%x\n", __func__, (cmd_resp >> 1) & 0xF);
+		ERROR("%s: STATUS_CMD_RESPONSE_ERROR: 0x%x\n", __func__, (cmd_resp >> 5) & 0x7);
+	}
+
+	/* read CMD_RESPONSE_STATUS*/
+	resp->cmd_resp_status = mmio_read_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	INFO("IOSSM: %s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n",
+		__func__, io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	/* read CMD_RESPONSE_DATA_* */
+	for (i = 0; i < resp_data_len; i++) {
+		switch (i) {
+		case 0:
+			resp->cmd_resp_data_0 =
+				mmio_read_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET);
+
+			break;
+		case 1:
+			resp->cmd_resp_data_1 =
+				mmio_read_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET);
+
+			break;
+		case 2:
+			resp->cmd_resp_data_2 =
+				mmio_read_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET);
+			break;
+		default:
+			ERROR("%s: Invalid response data\n", __func__);
+		}
+	}
+
+	resp->cmd_resp_status = mmio_read_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	INFO("IOSSM: %s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n",
+		__func__, io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	/* write CMD_RESPONSE_READY = 0 */
+	mmio_clrbits_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET,
+			IOSSM_STATUS_COMMAND_RESPONSE_READY);
+
+	resp->cmd_resp_status = mmio_read_32(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	INFO("IOSSM: %s: CMD_RESPONSE_READY 0x%llx: 0x%x\n",
+		__func__, io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	return 0;
+}
+
+/*
+ * Initial function to be called to set memory interface IP type and instance ID
+ * IP type and instance ID need to be determined before sending mailbox command
+ */
+void io96b_mb_init(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	uint8_t ip_type_ret, instance_id_ret;
+	int i, j, k;
+
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			/* Get memory interface IP type & instance ID (IP identifier) */
+			io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0,
+				     CMD_GET_SYS_INFO, GET_MEM_INTF_INFO, 0, 0,
+				     0, 0, 0, 0, 0, 2, &usr_resp);
+			/* Retrieve number of memory interface(s) */
+			io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface =
+				IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3;
+
+			/* Retrieve memory interface IP type and instance ID (IP identifier) */
+			j = 0;
+			for (k = 0; k < MAX_MEM_INTERFACES_SUPPORTED; k++) {
+				switch (k) {
+				case 0:
+					ip_type_ret = (usr_resp.cmd_resp_data_0 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_0 >> 24) & 0x1F;
+					break;
+				case 1:
+					ip_type_ret = (usr_resp.cmd_resp_data_1 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_1 >> 24) & 0x1F;
+					break;
+				}
+
+				if (ip_type_ret != 0) {
+					io96b_ctrl->io96b_0.mb_ctrl.ip_type[j] = ip_type_ret;
+					io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j] =
+						instance_id_ret;
+					j++;
+				}
+			}
+			break;
+		case 1:
+			/* Get memory interface IP type and instance ID (IP identifier) */
+			io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0, CMD_GET_SYS_INFO,
+				     GET_MEM_INTF_INFO, 0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+
+			/* Retrieve number of memory interface(s) */
+			io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface =
+				IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3;
+
+			/* Retrieve memory interface IP type and instance ID (IP identifier) */
+			j = 0;
+			for (k = 0; k < MAX_MEM_INTERFACES_SUPPORTED; k++) {
+				switch (k) {
+				case 0:
+					ip_type_ret = (usr_resp.cmd_resp_data_0 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_0 >> 24) & 0x1F;
+					break;
+				case 1:
+					ip_type_ret = (usr_resp.cmd_resp_data_1 >> 29) & 0x7;
+					instance_id_ret = (usr_resp.cmd_resp_data_1 >> 24) & 0x1F;
+					break;
+				}
+
+				if (ip_type_ret != 0) {
+					io96b_ctrl->io96b_1.mb_ctrl.ip_type[j] = ip_type_ret;
+					io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j] =
+						instance_id_ret;
+					j++;
+				}
+			}
+			break;
+		}
+
+	}
+}
+
+static inline void hang(void)
+{
+	ERROR("IOSSM: %s: system is going to die :(\n", __func__);
+	while (1)
+		;
+}
+
+int io96b_cal_status(phys_addr_t addr)
+{
+	int cal_busy_status, cal_success_status;
+	phys_addr_t status_addr = addr + IOSSM_STATUS_OFFSET;
+
+	/* Ensure calibration busy status */
+	cal_busy_status = wait_for_bit((const void *)status_addr, IOSSM_STATUS_CAL_BUSY,
+					false, 15000);
+	if (cal_busy_status != 0) {
+		ERROR("IOSSM: One or more EMIF instances are busy with calibration\n");
+		return -EBUSY;
+	}
+
+	/* Calibration success status check */
+	NOTICE("IOSSM: Calibration success status check...\n");
+	cal_success_status = wait_for_bit((const void *)status_addr, IOSSM_STATUS_CAL_SUCCESS,
+					  true, 15000);
+	if (cal_success_status != 0) {
+		ERROR("IOSSM: One/more EMIF instances either failed to calibrate/not completed\n");
+		return -EBUSY;
+	}
+
+	NOTICE("IOSSM: All EMIF instances within the IO96 have calibrated successfully!\n");
+	return 0;
+}
+
+void init_mem_cal(struct io96b_info *io96b_ctrl)
+{
+	int count, i, ret;
+
+	/* Initialize overall calibration status */
+	io96b_ctrl->overall_cal_status = false;
+
+	/* Check initial calibration status for the assigned IO96B */
+	count = 0;
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			ret = io96b_cal_status(io96b_ctrl->io96b_0.io96b_csr_addr);
+			if (ret != 0) {
+				io96b_ctrl->io96b_0.cal_status = false;
+				ERROR("%s: Initial DDR calibration IO96B_0 failed %d\n",
+					__func__, ret);
+				break;
+			}
+			io96b_ctrl->io96b_0.cal_status = true;
+			INFO("IOSSM: %s: Initial DDR calibration IO96B_0 succeed\n", __func__);
+			count++;
+			break;
+		case 1:
+			ret = io96b_cal_status(io96b_ctrl->io96b_1.io96b_csr_addr);
+			if (ret != 0) {
+				io96b_ctrl->io96b_1.cal_status = false;
+				ERROR("%s: Initial DDR calibration IO96B_1 failed %d\n",
+					__func__, ret);
+				break;
+			}
+			io96b_ctrl->io96b_1.cal_status = true;
+			INFO("IOSSM: %s: Initial DDR calibration IO96B_1 succeed\n", __func__);
+			count++;
+			break;
+		}
+	}
+
+	if (count == io96b_ctrl->num_instance)
+		io96b_ctrl->overall_cal_status = true;
+}
+
+/*
+ * Trying 3 times re-calibration if initial calibration failed
+ */
+int trig_mem_cal(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	bool recal_success;
+	int i;
+	uint8_t cal_stat;
+
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			if (!(io96b_ctrl->io96b_0.cal_status)) {
+				/* Get the memory calibration status for first memory interface */
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0,
+					     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0,
+					     0, 0, 0, 0, 0, 0, 2, &usr_resp);
+
+				recal_success = false;
+
+				/* Re-calibration first memory interface with failed calibration */
+				for (i = 0; i < 3; i++) {
+					cal_stat = usr_resp.cmd_resp_data_0 & GENMASK(2, 0);
+					if (cal_stat < 0x2) {
+						recal_success = true;
+						break;
+					}
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+						     io96b_ctrl->io96b_0.mb_ctrl.ip_type[0],
+						     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[0],
+						     CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0,
+						     0, 0, 0, 2, &usr_resp);
+					mdelay(1000);
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0,
+						     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS,
+						     0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+				}
+
+				if (!recal_success) {
+					ERROR("%s: Error as SDRAM calibration failed\n", __func__);
+					hang();
+				}
+
+				/* Get the memory calibration status for second memory interface */
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0,
+					     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0,
+					     0, 0, 0, 0, 2, &usr_resp);
+
+				recal_success = false;
+
+				/* Re-calibration second memory interface with failed calibration*/
+				for (i = 0; i < 3; i++) {
+					cal_stat = usr_resp.cmd_resp_data_1 & GENMASK(2, 0);
+					if (cal_stat < 0x2) {
+						recal_success = true;
+						break;
+					}
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+						     io96b_ctrl->io96b_0.mb_ctrl.ip_type[1],
+						     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[1],
+						     CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0,
+						     0, 0, 0, 2, &usr_resp);
+					mdelay(1000);
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr, 0, 0,
+						     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS,
+						     0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+				}
+
+				if (!recal_success) {
+					ERROR("IOSSMM: Error as SDRAM calibration failed\n");
+					hang();
+				}
+
+				io96b_ctrl->io96b_0.cal_status = true;
+			}
+			break;
+		case 1:
+			if (!(io96b_ctrl->io96b_1.cal_status)) {
+				/* Get the memory calibration status for first memory interface */
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0,
+					     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0,
+					     0, 0, 0, 0, 0, 0, 2, &usr_resp);
+
+				recal_success = false;
+
+				/* Re-calibration first memory interface with failed calibration */
+				for (i = 0; i < 3; i++) {
+					cal_stat = usr_resp.cmd_resp_data_0 & GENMASK(2, 0);
+					if (cal_stat < 0x2) {
+						recal_success = true;
+						break;
+					}
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+						     io96b_ctrl->io96b_1.mb_ctrl.ip_type[0],
+						     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[0],
+						     CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0,
+						     0, 0, 0, 2, &usr_resp);
+					mdelay(1000);
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0,
+						     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS,
+						     0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+				}
+
+				if (!recal_success) {
+					ERROR("IOSSM: Error as SDRAM calibration failed\n");
+					hang();
+				}
+
+				/* Get the memory calibration status for second memory interface */
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0,
+					     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS, 0, 0, 0,
+					     0, 0, 0, 0, 2, &usr_resp);
+
+				recal_success = false;
+
+				/* Re-calibration second memory interface with failed calibration*/
+				for (i = 0; i < 3; i++) {
+					cal_stat = usr_resp.cmd_resp_data_0 & GENMASK(2, 0);
+					if (cal_stat < 0x2) {
+						recal_success = true;
+						break;
+					}
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+						     io96b_ctrl->io96b_1.mb_ctrl.ip_type[1],
+						     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[1],
+						     CMD_TRIG_MEM_CAL_OP, TRIG_MEM_CAL, 0, 0, 0, 0,
+						     0, 0, 0, 2, &usr_resp);
+					mdelay(1000);
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr, 0, 0,
+						     CMD_TRIG_MEM_CAL_OP, GET_MEM_CAL_STATUS,
+						     0, 0, 0, 0, 0, 0, 0, 2, &usr_resp);
+				}
+
+				if (!recal_success) {
+					ERROR("IOSSM: Error as SDRAM calibration failed\n");
+					hang();
+				}
+
+				io96b_ctrl->io96b_1.cal_status = true;
+			}
+			break;
+		}
+	}
+
+	if (io96b_ctrl->io96b_0.cal_status && io96b_ctrl->io96b_1.cal_status) {
+		INFO("IOSSM: %s: Overall SDRAM calibration success\n", __func__);
+		io96b_ctrl->overall_cal_status = true;
+	}
+
+	return 0;
+}
+
+int get_mem_technology(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	uint8_t ddr_type_ret;
+
+	/* Initialize ddr type */
+	io96b_ctrl->ddr_type = ddr_type_list[6];
+
+	/* Get and ensure all memory interface(s) same DDR type */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j],
+					     CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, 0, 0, 0, 0,
+					     0, 0, 0, 0, &usr_resp);
+
+				ddr_type_ret =
+					IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 0);
+
+				if (strcmp(io96b_ctrl->ddr_type, "UNKNOWN") == 0)
+					io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret];
+
+				if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) {
+					ERROR("IOSSM: Mismatch DDR type on IO96B_0\n");
+					return -ENOEXEC;
+				}
+			}
+			break;
+		case 1:
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j],
+					     CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, 0, 0, 0,
+					     0, 0, 0, 0, 0, &usr_resp);
+
+				ddr_type_ret =
+					IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 0);
+
+				if (strcmp(io96b_ctrl->ddr_type, "UNKNOWN") == 0)
+					io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret];
+
+				if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) {
+					ERROR("IOSSM: Mismatch DDR type on IO96B_1\n");
+					return -ENOEXEC;
+				}
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int get_mem_width_info(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	uint16_t memory_size = 0U;
+	uint16_t total_memory_size = 0U;
+
+	/* Get all memory interface(s) total memory size on all instance(s) */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			memory_size = 0;
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j],
+					     CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, 0, 0, 0,
+					     0, 0, 0, 0, 2, &usr_resp);
+
+				memory_size = memory_size +
+						(usr_resp.cmd_resp_data_1 & GENMASK(7, 0));
+			}
+
+			if (memory_size == 0U) {
+				ERROR("IOSSM: %s: Failed to get valid memory size\n", __func__);
+				return -ENOEXEC;
+			}
+
+			io96b_ctrl->io96b_0.size = memory_size;
+
+			break;
+		case 1:
+			memory_size = 0;
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j],
+					     CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, 0, 0, 0,
+					     0, 0, 0, 0, 2, &usr_resp);
+
+				memory_size = memory_size +
+						(usr_resp.cmd_resp_data_1 & GENMASK(7, 0));
+			}
+
+			if (memory_size == 0U) {
+				ERROR("IOSSM: %s: Failed to get valid memory size\n", __func__);
+				return -ENOEXEC;
+			}
+
+			io96b_ctrl->io96b_1.size = memory_size;
+
+			break;
+		}
+
+		total_memory_size = total_memory_size + memory_size;
+	}
+
+	if (total_memory_size == 0U) {
+		ERROR("IOSSM: %s: Failed to get valid memory size\n", __func__);
+		return -ENOEXEC;
+	}
+
+	io96b_ctrl->overall_size = total_memory_size;
+
+	return 0;
+}
+
+int ecc_enable_status(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	bool ecc_stat_set = false;
+	bool ecc_stat;
+
+	/* Initialize ECC status */
+	io96b_ctrl->ecc_status = false;
+
+	/* Get and ensure all memory interface(s) same ECC status */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j],
+					     CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS, 0, 0,
+					     0, 0, 0, 0, 0, 0, &usr_resp);
+
+				ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+						& GENMASK(1, 0)) == 0 ? false : true);
+
+				if (!ecc_stat_set) {
+					io96b_ctrl->ecc_status = ecc_stat;
+					ecc_stat_set = true;
+				}
+
+				if (ecc_stat != io96b_ctrl->ecc_status) {
+					ERROR("IOSSM: %s: Mismatch DDR ECC status on IO96B_0\n",
+						__func__);
+					return -ENOEXEC;
+				}
+			}
+			break;
+		case 1:
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j],
+					     CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS, 0, 0,
+					     0, 0, 0, 0, 0, 0, &usr_resp);
+
+				ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+						& GENMASK(1, 0)) == 0 ? false : true);
+
+				if (!ecc_stat_set) {
+					io96b_ctrl->ecc_status = ecc_stat;
+					ecc_stat_set = true;
+				}
+
+				if (ecc_stat != io96b_ctrl->ecc_status) {
+					ERROR("%s: Mismatch DDR ECC status on IO96B_1\n"
+						, __func__);
+					return -ENOEXEC;
+				}
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+int bist_mem_init_start(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	bool bist_start, bist_success;
+	uint32_t read_count;
+	uint32_t read_interval_ms;
+
+	/* Full memory initialization BIST performed on all memory interface(s) */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		switch (i) {
+		case 0:
+			for (j = 0; j < io96b_ctrl->io96b_0.mb_ctrl.num_mem_interface; j++) {
+				bist_start = false;
+				bist_success = false;
+				read_interval_ms = 500U;
+
+				/* Start memory initialization BIST on full memory address */
+				io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j],
+					     CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0x40,
+					     0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+				bist_start =
+					(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& 1);
+
+				if (!bist_start) {
+					ERROR("IOSSM: %s: Failed to initialized memory on IO96B_0\n"
+					, __func__);
+					ERROR("IOSSM: %s: BIST_MEM_INIT_START Error code 0x%x\n",
+					__func__,
+					(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 1)) > 0x1);
+					return -ENOEXEC;
+				}
+
+				/* Polling for the initiated memory initialization BIST status */
+				read_count = read_interval_ms / TIMEOUT;
+				while (!bist_success) {
+					io96b_mb_req(io96b_ctrl->io96b_0.io96b_csr_addr,
+						     io96b_ctrl->io96b_0.mb_ctrl.ip_type[j],
+						     io96b_ctrl->io96b_0.mb_ctrl.ip_instance_id[j],
+						     CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_STATUS,
+						     0, 0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+					bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT
+							(usr_resp.cmd_resp_status) & 1);
+
+					if ((!bist_success) && (read_count == 0U)) {
+						ERROR("IOSSM: %s: Timeout init memory on IO96B_0\n"
+							, __func__);
+						ERROR("IOSSM: %s: BIST_MEM_INIT_STATUS Err code%x\n"
+							, __func__, (IOSSM_CMD_RESPONSE_DATA_SHORT
+							(usr_resp.cmd_resp_status)
+							& GENMASK(2, 1)) > 0x1);
+						return -ETIMEDOUT;
+					}
+					read_count--;
+					mdelay(read_interval_ms);
+				}
+			}
+
+			NOTICE("IOSSM: %s: Memory initialized successfully on IO96B_0\n", __func__);
+			break;
+
+		case 1:
+			for (j = 0; j < io96b_ctrl->io96b_1.mb_ctrl.num_mem_interface; j++) {
+				bist_start = false;
+				bist_success = false;
+				read_interval_ms = 500U;
+
+				/* Start memory initialization BIST on full memory address */
+				io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_type[j],
+					     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j],
+					     CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START, 0x40,
+					     0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+				bist_start =
+					(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& 1);
+
+				if (!bist_start) {
+					ERROR("IOSSM: %s: Failed to initialized memory on IO96B_1\n"
+						, __func__);
+					ERROR("IOSSM: %s: BIST_MEM_INIT_START Error code 0x%x\n",
+					__func__,
+					(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 1)) > 0x1);
+					return -ENOEXEC;
+				}
+
+				/* Polling for the initiated memory initialization BIST status */
+				read_count = read_interval_ms / TIMEOUT;
+				while (!bist_success) {
+					io96b_mb_req(io96b_ctrl->io96b_1.io96b_csr_addr,
+						     io96b_ctrl->io96b_1.mb_ctrl.ip_type[j],
+						     io96b_ctrl->io96b_1.mb_ctrl.ip_instance_id[j],
+						     CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_STATUS,
+						     0, 0, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+					bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT
+							(usr_resp.cmd_resp_status) & 1);
+
+					if ((!bist_success) && (read_count == 0U)) {
+						ERROR("IOSSM: %s: Timeout init memory on IO96B_1\n"
+							, __func__);
+						ERROR("IOSSM: %s: BIST_MEM_INIT_STATUS ErrCode %x\n"
+							, __func__, (IOSSM_CMD_RESPONSE_DATA_SHORT
+							(usr_resp.cmd_resp_status)
+							& GENMASK(2, 1)) > 0x1);
+						return -ETIMEDOUT;
+					}
+					read_count--;
+					mdelay(read_interval_ms);
+				}
+			}
+
+			NOTICE("IOSSM: %s: Memory initialized successfully on IO96B_1\n", __func__);
+			break;
+		}
+	}
+	return 0;
+}
diff --git a/plat/intel/soc/agilex5/soc/agilex5_pinmux.c b/plat/intel/soc/agilex5/soc/agilex5_pinmux.c
index 50d9e36..7c4eb57 100644
--- a/plat/intel/soc/agilex5/soc/agilex5_pinmux.c
+++ b/plat/intel/soc/agilex5/soc/agilex5_pinmux.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -195,11 +196,15 @@
 {
 	unsigned int i;
 
-	mmio_write_32(PINMUX_HANDOFF_CONFIG_ADDR, PINMUX_HANDOFF_CONFIG_VAL);
-	for (i = 0; i < PINMUX_HANDOFF_ARRAY_SIZE(hoff_ptr->pinmux_sel_array); i += 2) {
-		mmio_write_32(AGX5_PINMUX_PIN0SEL +
-			hoff_ptr->pinmux_sel_array[i],
-			hoff_ptr->pinmux_sel_array[i + 1]);
+	/*
+	 * Configure the FPGA use.
+	 * The actual generic handoff contains extra 4 elements, and these 4 elements
+	 * are not applicable to the Agilex5 platform. Writing these extra 4 elements
+	 * will cause the system to crash, so let's avoid writing them here.
+	 */
+	for (i = 0; i < (ARRAY_SIZE(hoff_ptr->pinmux_fpga_array) - 4); i += 2) {
+		mmio_write_32(AGX5_PINMUX_EMAC0_USEFPGA + hoff_ptr->pinmux_fpga_array[i],
+			      hoff_ptr->pinmux_fpga_array[i+1]);
 	}
 
 	config_fpgaintf_mod();
diff --git a/plat/intel/soc/common/include/socfpga_handoff.h b/plat/intel/soc/common/include/socfpga_handoff.h
index b2913c7..7e1d0c0 100644
--- a/plat/intel/soc/common/include/socfpga_handoff.h
+++ b/plat/intel/soc/common/include/socfpga_handoff.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,12 +11,12 @@
 #define HANDOFF_MAGIC_HEADER			0x424f4f54	/* BOOT */
 #define HANDOFF_MAGIC_PINMUX_SEL		0x504d5558	/* PMUX */
 #define HANDOFF_MAGIC_IOCTLR			0x494f4354	/* IOCT */
-#define HANDOFF_MAGIC_FPGA				0x46504741	/* FPGA */
+#define HANDOFF_MAGIC_FPGA			0x46504741	/* FPGA */
 #define HANDOFF_MAGIC_IODELAY			0x444c4159	/* DLAY */
-#define HANDOFF_MAGIC_CLOCK				0x434c4b53	/* CLKS */
-#define HANDOFF_MAGIC_MISC				0x4d495343	/* MISC */
+#define HANDOFF_MAGIC_CLOCK			0x434c4b53	/* CLKS */
+#define HANDOFF_MAGIC_MISC			0x4d495343	/* MISC */
 #define HANDOFF_MAGIC_PERIPHERAL		0x50455249	/* PERIPHERAL */
-#define HANDOFF_MAGIC_DDR				0x5344524d	/* DDR */
+#define HANDOFF_MAGIC_DDR			0x5344524d	/* DDR */
 
 #include <socfpga_plat_def.h>
 
@@ -126,6 +127,8 @@
 	uint32_t	clock_magic;
 	uint32_t	clock_length;
 	uint32_t	_pad_0x588_0x590[2];
+
+	/* main group PLL */
 	uint32_t	main_pll_nocclk;
 	uint32_t	main_pll_nocdiv;
 	uint32_t	main_pll_pllglob;
@@ -135,6 +138,8 @@
 	uint32_t	main_pll_pllc2;
 	uint32_t	main_pll_pllc3;
 	uint32_t	main_pll_pllm;
+
+	/* peripheral group PLL */
 	uint32_t	per_pll_emacctl;
 	uint32_t	per_pll_gpiodiv;
 	uint32_t	per_pll_pllglob;
@@ -144,29 +149,25 @@
 	uint32_t	per_pll_pllc2;
 	uint32_t	per_pll_pllc3;
 	uint32_t	per_pll_pllm;
+
+	/* control group */
 	uint32_t	alt_emacactr;
 	uint32_t	alt_emacbctr;
 	uint32_t	alt_emacptpctr;
 	uint32_t	alt_gpiodbctr;
-	uint32_t	alt_sdmmcctr;
 	uint32_t	alt_s2fuser0ctr;
 	uint32_t	alt_s2fuser1ctr;
 	uint32_t	alt_psirefctr;
-	/* TODO: Temp added for clk manager. */
-	uint32_t	qspi_clk_khz;
+	uint32_t	alt_usb31ctr;
+	uint32_t	alt_dsuctr;
+	uint32_t	alt_core01ctr;
+	uint32_t	alt_core23ctr;
+	uint32_t	alt_core2ctr;
+	uint32_t	alt_core3ctr;
 	uint32_t	hps_osc_clk_hz;
 	uint32_t	fpga_clk_hz;
-	/* TODO: Temp added for clk manager. */
-	uint32_t	ddr_reset_type;
-	/* TODO: Temp added for clk manager. */
-	uint32_t	hps_status_coldreset;
-	/* TODO: Temp remove due to add in extra handoff data */
-	//uint32_t	_pad_0x604_0x610[3];
+	uint32_t	_pad_0x604_0x610[3];
 #endif
-	/* misc configuration */
-	uint32_t	misc_magic;
-	uint32_t	misc_length;
-	uint32_t	_pad_0x618_0x620[2];
 
 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5
 	/* peripheral configuration - select */
@@ -179,7 +180,7 @@
 	uint32_t	ddr_magic;
 	uint32_t	ddr_length;
 	uint32_t	_pad_0x1C_0x20[2];
-	uint32_t	ddr_array[4];	/* offset, value */
+	uint32_t	ddr_config;	/* BIT[0]-Dual Port. BIT[1]-Dual EMIF */
 #endif
 } handoff;
 
diff --git a/plat/intel/soc/common/soc/socfpga_mailbox.c b/plat/intel/soc/common/soc/socfpga_mailbox.c
index 74ecc95..5d31e99 100644
--- a/plat/intel/soc/common/soc/socfpga_mailbox.c
+++ b/plat/intel/soc/common/soc/socfpga_mailbox.c
@@ -168,7 +168,7 @@
 		}
 
 		if (MBOX_RESP_ERR(resp_data) > 0U) {
-			INFO("Error in response: %x\n", resp_data);
+			INFO("SDM response: Return Code: 0x%x\n", MBOX_RESP_ERR(resp_data));
 			return -MBOX_RESP_ERR(resp_data);
 		}
 
@@ -337,7 +337,7 @@
 			}
 
 			if (MBOX_RESP_ERR(resp_data) > 0U) {
-				INFO("Error in response: %x\n", resp_data);
+				INFO("SDM response: Return Code: 0x%x\n", MBOX_RESP_ERR(resp_data));
 				return -MBOX_RESP_ERR(resp_data);
 			}
 
@@ -652,7 +652,7 @@
 
 	res = response[RECONFIG_STATUS_SOFTFUNC_STATUS];
 	if ((res & SOFTFUNC_STATUS_SEU_ERROR) != 0U) {
-		ERROR("SoftFunction Status SEU ERROR\n");
+		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
 	}
 
 	if ((res & SOFTFUNC_STATUS_CONF_DONE) == 0U) {
diff --git a/plat/intel/soc/common/soc/socfpga_reset_manager.c b/plat/intel/soc/common/soc/socfpga_reset_manager.c
index cb4a210..c7d7076 100644
--- a/plat/intel/soc/common/soc/socfpga_reset_manager.c
+++ b/plat/intel/soc/common/soc/socfpga_reset_manager.c
@@ -76,7 +76,7 @@
 			RSTMGR_FIELD(PER0, DMAIF6) |
 			RSTMGR_FIELD(PER0, DMAIF7));
 
-#if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX
+#if (PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX) || (PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5)
 	mmio_clrbits_32(SOCFPGA_RSTMGR(BRGMODRST),
 			RSTMGR_FIELD(BRG, MPFE));
 #endif
@@ -484,6 +484,11 @@
 				(~brg_lst & (RSTMGR_BRGMODRST_SOC2FPGA
 				| RSTMGR_BRGMODRST_LWHPS2FPGA))
 				| RSTMGR_BRGMODRST_SOC2FPGA);
+
+		/* Set System Manager soc bridge control register[soc2fpga_ready_latency_enable] = 1 */
+		VERBOSE("Set SOC soc2fpga_ready_latency_enable ...\n");
+		mmio_setbits_32(SOCFPGA_SYSMGR(FPGA_BRIDGE_CTRL),
+			SYSMGR_SOC_BRIDGE_CTRL_EN);
 	}
 
 /**************** LWSOCFPGA ****************/
@@ -567,6 +572,11 @@
 				((~brg_lst & (RSTMGR_BRGMODRST_SOC2FPGA
 				| RSTMGR_BRGMODRST_LWHPS2FPGA)))
 				| RSTMGR_BRGMODRST_LWHPS2FPGA);
+
+		/* Set System Manager lwsoc bridge control register[lwsoc2fpga_ready_latency_enable] = 1 */
+		VERBOSE("Set LWSOC lwsoc2fpga_ready_latency_enable ...\n");
+		mmio_setbits_32(SOCFPGA_SYSMGR(FPGA_BRIDGE_CTRL),
+			SYSMGR_LWSOC_BRIDGE_CTRL_EN);
 	}
 #else
 	if (brg_mask != 0U) {
@@ -580,9 +590,6 @@
 		/* Wait until idle ack becomes 0 */
 		ret_hps = poll_idle_status(SOCFPGA_SYSMGR(NOC_IDLEACK),
 				       noc_mask, 0, 1000);
-		if (ret_hps < 0) {
-			ERROR("S2F bridge enable: Timeout idle ack\n");
-		}
 	}
 #endif
 
@@ -958,6 +965,11 @@
 		mmio_setbits_32(SOCFPGA_RSTMGR(BRGMODRST),
 			RSTMGR_BRGMODRST_SOC2FPGA);
 
+		/* Clear System Manager soc bridge control register[soc2fpga_ready_latency_enable] = 1 */
+		VERBOSE("Clear SOC soc2fpga_ready_latency_enable ...\n");
+		mmio_clrbits_32(SOCFPGA_SYSMGR(FPGA_BRIDGE_CTRL),
+			SYSMGR_SOC_BRIDGE_CTRL_EN);
+
 		udelay(1000);
 	}
 
@@ -991,6 +1003,11 @@
 		mmio_setbits_32(SOCFPGA_RSTMGR(BRGMODRST),
 			RSTMGR_BRGMODRST_LWHPS2FPGA);
 
+		/* Clear System Manager lwsoc bridge control register[lwsoc2fpga_ready_latency_enable] = 1 */
+		VERBOSE("Clear LWSOC lwsoc2fpga_ready_latency_enable ...\n");
+		mmio_clrbits_32(SOCFPGA_SYSMGR(FPGA_BRIDGE_CTRL),
+			SYSMGR_LWSOC_BRIDGE_CTRL_EN);
+
 		udelay(1000);
 	}
 #else
@@ -1266,4 +1283,4 @@
 	} while (timeout-- > 0);
 
 	return RSTMGR_RET_ERROR;
-}
+}
\ No newline at end of file
diff --git a/plat/intel/soc/common/socfpga_delay_timer.c b/plat/intel/soc/common/socfpga_delay_timer.c
index db173a4..3759009 100644
--- a/plat/intel/soc/common/socfpga_delay_timer.c
+++ b/plat/intel/soc/common/socfpga_delay_timer.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,7 +11,6 @@
 #include <lib/mmio.h>
 #include "socfpga_plat_def.h"
 
-
 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX
 #include "agilex_clock_manager.h"
 #elif PLATFORM_MODEL == PLAT_SOCFPGA_N5X
@@ -19,7 +19,7 @@
 #include "s10_clock_manager.h"
 #endif
 
-#define SOCFPGA_GLOBAL_TIMER		0xffd01000
+#define SOCFPGA_GLOBAL_TIMER		PLAT_TIMER_BASE_ADDR
 #define SOCFPGA_GLOBAL_TIMER_EN		0x3
 
 static timer_ops_t plat_timer_ops;
@@ -44,7 +44,6 @@
 	plat_timer_ops.clk_div		= PLAT_SYS_COUNTER_FREQ_IN_MHZ;
 
 	timer_init(&plat_timer_ops);
-
 }
 
 void socfpga_delay_timer_init(void)
@@ -54,5 +53,4 @@
 
 	asm volatile("msr cntp_ctl_el0, %0" : : "r" (SOCFPGA_GLOBAL_TIMER_EN));
 	asm volatile("msr cntp_tval_el0, %0" : : "r" (~0));
-
 }
diff --git a/plat/intel/soc/common/socfpga_image_load.c b/plat/intel/soc/common/socfpga_image_load.c
index a5c3279..ee79158 100644
--- a/plat/intel/soc/common/socfpga_image_load.c
+++ b/plat/intel/soc/common/socfpga_image_load.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,7 +13,13 @@
  ******************************************************************************/
 void plat_flush_next_bl_params(void)
 {
+	/*
+	 * We cannot flush these descriptors on the Agilex5 platform,
+	 * since the BL2 runs on the OCRAM and this OCRAM is not cache coherent.
+	 */
+#if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5
 	flush_bl_params_desc();
+#endif
 }
 
 /*******************************************************************************
diff --git a/plat/intel/soc/n5x/include/n5x_clock_manager.h b/plat/intel/soc/n5x/include/n5x_clock_manager.h
index 54477da..95a3d5c 100644
--- a/plat/intel/soc/n5x/include/n5x_clock_manager.h
+++ b/plat/intel/soc/n5x/include/n5x_clock_manager.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,7 +10,6 @@
 
 
 /* MACRO DEFINITION */
-#define SOCFPGA_GLOBAL_TIMER				0xffd01000
 #define SOCFPGA_GLOBAL_TIMER_EN				0x3
 
 #define CLKMGR_PLLGLOB_VCO_PSRC_MASK			GENMASK(17, 16)
diff --git a/plat/intel/soc/n5x/include/socfpga_plat_def.h b/plat/intel/soc/n5x/include/socfpga_plat_def.h
index 1eafeef..1b662ad 100644
--- a/plat/intel/soc/n5x/include/socfpga_plat_def.h
+++ b/plat/intel/soc/n5x/include/socfpga_plat_def.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
  * Copyright (c) 2020-2023, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,6 +19,7 @@
 #define PLAT_PRIMARY_CPU			0
 #define PLAT_CLUSTER_ID_MPIDR_AFF_SHIFT		MPIDR_AFF1_SHIFT
 #define PLAT_CPU_ID_MPIDR_AFF_SHIFT		MPIDR_AFF0_SHIFT
+#define PLAT_TIMER_BASE_ADDR			0xFFD01000
 
 /* FPGA config helpers */
 #define INTEL_SIP_SMC_FPGA_CONFIG_ADDR		0x400000
diff --git a/plat/intel/soc/stratix10/include/s10_memory_controller.h b/plat/intel/soc/stratix10/include/s10_memory_controller.h
index 155b279..056f6cf 100644
--- a/plat/intel/soc/stratix10/include/s10_memory_controller.h
+++ b/plat/intel/soc/stratix10/include/s10_memory_controller.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,7 +27,7 @@
 #define S10_MPFE_HMC_ADP_ECCCTRL1			0xf8011100
 #define S10_MPFE_HMC_ADP_ECCCTRL2			0xf8011104
 #define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT		0xf8011218
-#define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE	0x000000ff
+#define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE	0x0000000f
 #define S10_MPFE_HMC_ADP_RSTHANDSHAKECTRL		0xf8011214
 
 
diff --git a/plat/intel/soc/stratix10/include/socfpga_plat_def.h b/plat/intel/soc/stratix10/include/socfpga_plat_def.h
index 7f452bd..d4c7dab 100644
--- a/plat/intel/soc/stratix10/include/socfpga_plat_def.h
+++ b/plat/intel/soc/stratix10/include/socfpga_plat_def.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024, Altera Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,6 +18,7 @@
 #define PLAT_PRIMARY_CPU			0
 #define PLAT_CLUSTER_ID_MPIDR_AFF_SHIFT		MPIDR_AFF1_SHIFT
 #define PLAT_CPU_ID_MPIDR_AFF_SHIFT		MPIDR_AFF0_SHIFT
+#define PLAT_TIMER_BASE_ADDR			0xFFD01000
 
 /* FPGA config helpers */
 #define INTEL_SIP_SMC_FPGA_CONFIG_ADDR		0x400000
diff --git a/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
index 26bed29..7b867d8 100644
--- a/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
+++ b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
@@ -97,7 +97,7 @@
 
 	/* PCI-e protect address(64MB) */
 	region_info.start = 0xC0000000ULL;
-	region_info.end = 0xC3FF0000ULL;
+	region_info.end = 0xC3FFFFFFULL;
 	region_info.region = 1;
 	SET_ACCESS_PERMISSION(region_info.apc, 1,
 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
@@ -108,7 +108,7 @@
 
 	/* SCP protect address */
 	region_info.start = 0x50000000ULL;
-	region_info.end = 0x513F0000ULL;
+	region_info.end = 0x513FFFFFULL;
 	region_info.region = 2;
 	SET_ACCESS_PERMISSION(region_info.apc, 1,
 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
@@ -117,21 +117,10 @@
 			      NO_PROT, FORBIDDEN, FORBIDDEN, NO_PROT);
 	emi_mpu_set_protection(&region_info);
 
-	/* DSP protect address */
-	region_info.start = 0x40000000ULL;	/* dram base addr */
-	region_info.end = 0x1FFFF0000ULL;
-	region_info.region = 3;
-	SET_ACCESS_PERMISSION(region_info.apc, 1,
-			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
-			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
-			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
-			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROT);
-	emi_mpu_set_protection(&region_info);
-
 	/* Forbidden All */
 	region_info.start = 0x40000000ULL;	/* dram base addr */
-	region_info.end = 0x1FFFF0000ULL;
-	region_info.region = 4;
+	region_info.end = 0x1FFFFFFFFULL;
+	region_info.region = 3;
 	SET_ACCESS_PERMISSION(region_info.apc, 1,
 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
diff --git a/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
index b6e5a2d..8e4a675 100644
--- a/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
+++ b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
@@ -118,7 +118,7 @@
 
 	/* SCP DRAM */
 	region_info.start = 0x50000000ULL;
-	region_info.end = 0x51400000ULL;
+	region_info.end = 0x513FFFFFULL;
 	region_info.region = 2;
 	SET_ACCESS_PERMISSION(region_info.apc, 1,
 			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
diff --git a/plat/xilinx/common/include/plat_console.h b/plat/xilinx/common/include/plat_console.h
index 0f8320e..fa6021d 100644
--- a/plat/xilinx/common/include/plat_console.h
+++ b/plat/xilinx/common/include/plat_console.h
@@ -8,18 +8,30 @@
 #define PLAT_DT_UART_H
 
 #define DT_UART_DCC_COMPAT	"arm,dcc"
+#define DT_UART_CAD_COMPAT	"xlnx,zynqmp-uart"
+#define DT_UART_PL011_COMPAT	"arm,pl011"
 
-#if defined(PLAT_zynqmp)
-#define DT_UART_COMPAT	"xlnx,zynqmp-uart"
-#else
-#define DT_UART_COMPAT	"arm,pl011"
-#endif
+/* Default console type is either CADENCE0 or CADENCE1 or PL011_0 or PL011_1
+ * Debug console type is DCC
+ */
+#define CONSOLE_NONE	0
+#define CONSOLE_CDNS	1
+#define CONSOLE_PL011   2
+#define CONSOLE_DCC	3
+
+typedef struct console_hd {
+	uint32_t clk;
+	uint32_t baud_rate;
+	uintptr_t base;
+	uint32_t console_scope;
+	uint8_t console_type;
+} console_holder;
 
 typedef struct dt_uart_info_s {
 	char compatible[30];
 	uintptr_t base;
 	uint32_t baud_rate;
-	int32_t status;
+	uint8_t console_type;
 } dt_uart_info_t;
 
 void setup_console(void);
diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
index 6265928..0ea51f0 100644
--- a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -106,11 +106,11 @@
 		SMC_RET1(handle, 0);
 	case IPI_MAILBOX_STATUS_ENQUIRY:
 	{
-		int32_t disable_irq;
+		int32_t disable_interrupt;
 
-		disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0;
+		disable_interrupt = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0;
 		ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id);
-		if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq)
+		if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_interrupt)
 			ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
 		SMC_RET1(handle, ret);
 	}
@@ -124,11 +124,11 @@
 	}
 	case IPI_MAILBOX_ACK:
 	{
-		int32_t enable_irq;
+		int32_t enable_interrupt;
 
-		enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0;
+		enable_interrupt = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0;
 		ipi_mb_ack(ipi_local_id, ipi_remote_id);
-		if (enable_irq)
+		if (enable_interrupt)
 			ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
 		SMC_RET1(handle, 0);
 	}
diff --git a/plat/xilinx/common/plat_console.c b/plat/xilinx/common/plat_console.c
index b84912a..681226f 100644
--- a/plat/xilinx/common/plat_console.c
+++ b/plat/xilinx/common/plat_console.c
@@ -23,9 +23,64 @@
 #include <platform_def.h>
 #include <plat_private.h>
 
-static console_t console;
+#if !(CONSOLE_IS(none))
+static console_t boot_console;
+static console_holder boot_hd_console;
+#if defined(CONSOLE_RUNTIME)
+static console_t runtime_console;
+static console_holder rt_hd_console;
+#endif
+
+#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
+	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
+				   !IS_TFA_IN_OCM(BL31_BASE)))
+static dt_uart_info_t dt_uart_info;
+#endif
+
+/**
+ * register_console() - Registers the uart with console list.
+ * @consoleh: Console holder structure with UART base address,
+ *  UART clock, UART buad rate, flags & console type
+ * @console: Pointer to the console information structure.
+ */
+static void register_console(const console_holder *consoleh, console_t *console)
+{
+	int32_t rc = 0;
+
+	switch (consoleh->console_type) {
+#if defined(PLAT_zynqmp)
+	case CONSOLE_CDNS:
+		rc = console_cdns_register(consoleh->base,
+				consoleh->clk,
+				consoleh->baud_rate,
+				console);
+		break;
+#else
+	case CONSOLE_PL011:
+		rc = console_pl011_register(consoleh->base,
+				consoleh->clk,
+				consoleh->baud_rate,
+				console);
+		break;
+#endif
+	case CONSOLE_DCC:
+		rc = console_dcc_register(console);
+		break;
+	default:
+		INFO("Invalid console type\n");
+		break;
+	}
 
-#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
+	if (rc == 0) {
+		panic();
+	}
+
+	console_set_scope(console, consoleh->console_scope);
+}
+
+#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
+	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
+				   !IS_TFA_IN_OCM(BL31_BASE)))
 /**
  * get_baudrate() - Get the baudrate form DTB.
  * @dtb: Address of the Device Tree Blob (DTB).
@@ -103,34 +158,56 @@
  * @node: Node address in the device tree.
  * @dtb: Address of the Device Tree Blob(DTB).
  *
- * Return: On success, it returns 1; on failure, it returns an 0.
+ * Return: On success, it returns 0; on failure, it returns -1 or -FDT_ERR_NOTFOUND.
  */
-static uint32_t fdt_add_uart_info(dt_uart_info_t *info, int node, void *dtb)
+static int32_t fdt_add_uart_info(dt_uart_info_t *info, int node, void *dtb)
 {
 	uintptr_t base_addr;
 	const char *com;
 	int32_t ret = 0;
+	uint32_t status;
 
 	com = fdt_getprop(dtb, node, "compatible", NULL);
 	if (com != NULL) {
 		strlcpy(info->compatible, com, sizeof(info->compatible));
 	} else {
 		ERROR("Compatible property not found in DTB node\n");
-		ret  = -FDT_ERR_NOTFOUND;
+		ret = -FDT_ERR_NOTFOUND;
 		goto error;
 	}
 
-	ret = fdt_get_reg_props_by_index(dtb, node, 0, &base_addr, NULL);
-	if (ret >= 0) {
-		info->base = base_addr;
-	} else {
-		ERROR("Failed to retrieve base address. Error code: %d\n", ret);
-		ret  = -FDT_ERR_NOTFOUND;
+	status = get_node_status(dtb, node);
+	if (status == 0) {
+		ERROR("Uart node is disabled in DTB\n");
+		ret = -FDT_ERR_NOTFOUND;
 		goto error;
 	}
 
+	if (strncmp(info->compatible, DT_UART_DCC_COMPAT, strlen(DT_UART_DCC_COMPAT)) != 0) {
+		ret = fdt_get_reg_props_by_index(dtb, node, 0, &base_addr, NULL);
+		if (ret >= 0) {
+			info->base = base_addr;
+		} else {
+			ERROR("Failed to retrieve base address. Error code: %d\n", ret);
+			ret = -FDT_ERR_NOTFOUND;
+			goto error;
+		}
+
-	info->status = get_node_status(dtb, node);
-	info->baud_rate = get_baudrate(dtb);
+		info->baud_rate = get_baudrate(dtb);
+
+		if (strncmp(info->compatible, DT_UART_CAD_COMPAT,
+					strlen(DT_UART_CAD_COMPAT)) == 0) {
+			info->console_type = CONSOLE_CDNS;
+		} else if (strncmp(info->compatible, DT_UART_PL011_COMPAT,
+					strlen(DT_UART_PL011_COMPAT)) == 0) {
+			info->console_type = CONSOLE_PL011;
+		} else {
+			ERROR("Incompatible uart node in DTB\n");
+			ret = -FDT_ERR_NOTFOUND;
+		}
+	} else {
+		info->console_type = CONSOLE_DCC;
+	}
 
 error:
 	return ret;
@@ -150,194 +227,87 @@
 	ret = is_valid_dtb(dtb);
 	if (ret < 0) {
 		ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
-		ret  = -FDT_ERR_NOTFOUND;
 		goto error;
 	}
 
 	node = fdt_get_stdout_node_offset(dtb);
 	if (node < 0) {
 		ERROR("DT get stdout node failed : %d\n", node);
-		ret  = -FDT_ERR_NOTFOUND;
 		goto error;
 	}
 
 	ret = fdt_add_uart_info(info, node, dtb);
 	if (ret < 0) {
 		ERROR("Failed to add DT UART info: %d\n", ret);
-		ret  = -FDT_ERR_NOTFOUND;
-		goto error;
-	}
-
-error:
-	return ret;
-}
-
-/**
- * check_fdt_uart_info() - Check early uart info with DTB uart info.
- * @info: Pointer to the UART information structure.
- *
- * Return: On success, it returns 0; on failure, it returns an error+reason.
- */
-static int32_t check_fdt_uart_info(dt_uart_info_t *info)
-{
-	int32_t ret = 0;
-
-	if (info->status == 0) {
-		ret = -ENODEV;
-		goto error;
-	}
-
-	if ((info->base == console.base) &&
-	   (info->baud_rate == UART_BAUDRATE) && !CONSOLE_IS(dcc)) {
-		ret = -ENODEV;
 		goto error;
 	}
 
 error:
 	return ret;
 }
-
-/**
- * console_boot_end() - Unregister the console_t instance form the console list.
- * @boot_console: Pointer to the console information structure.
- */
-static void console_boot_end(console_t *boot_console)
-{
-	if (CONSOLE_IS(dcc)) {
-		console_dcc_unregister();
-	} else {
-		console_flush();
-		(void)console_unregister(boot_console);
-	}
-}
-
-/**
- * setup_runtime_console() - Registers the runtime uart with console list.
- * @clock: UART clock.
- * @info: Pointer to the UART information structure.
- */
-static void setup_runtime_console(uint32_t clock, dt_uart_info_t *info)
-{
-	static console_t bl31_runtime_console;
-	int32_t rc;
-
-#if defined(PLAT_zynqmp)
-	rc = console_cdns_register(info->base,
-				   clock,
-				   info->baud_rate,
-				   &bl31_runtime_console);
-#else
-	rc = console_pl011_register(info->base,
-				    clock,
-				    info->baud_rate,
-				    &bl31_runtime_console);
 #endif
-	if (rc == 0) {
-		panic();
-	}
-
-	console_set_scope(&bl31_runtime_console,
-			  CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME |
-			  CONSOLE_FLAG_CRASH);
-}
 
-
-/**
- * runtime_console_init() - Initializes the run time console information.
- * @uart_info: Pointer to the UART information structure.
- * @bl31_boot_console: Pointer to the console information structure.
- * @clock: UART clock.
- *
- * Return: On success, it returns 0; on failure, it returns an error+reason;
- */
-static int32_t runtime_console_init(dt_uart_info_t *uart_info,
-			  console_t *bl31_boot_console,
-			  uint32_t clock)
+void setup_console(void)
 {
-	int32_t rc = 0;
+	/* This is hardcoded console setup just in case that DTB console fails */
+	boot_hd_console.base = (uintptr_t)UART_BASE;
+	boot_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
+	boot_hd_console.clk = get_uart_clk();
+	boot_hd_console.console_scope = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH;
+	boot_hd_console.console_type = UART_TYPE;
 
-	/* Parse UART information from Device Tree Blob (DTB) */
-	rc = fdt_get_uart_info(uart_info);
-	if (rc < 0) {
-		rc = -FDT_ERR_NOTFOUND;
-		goto error;
-	}
+	/* For DT code decoding uncomment console registration below */
+	/* register_console(&boot_hd_console, &boot_console); */
 
-	if (strncmp(uart_info->compatible, DT_UART_COMPAT,
-		   strlen(DT_UART_COMPAT)) == 0) {
-
-		if (check_fdt_uart_info(uart_info) == 0) {
-			setup_runtime_console(clock, uart_info);
-			console_boot_end(bl31_boot_console);
-			INFO("Runtime console setup\n");
-		} else {
-			INFO("Early console and DTB console are same\n");
+#if ((CONSOLE_IS(dtb) || RT_CONSOLE_IS(dtb)) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
+	(!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
+				   !IS_TFA_IN_OCM(BL31_BASE)))
+	/* Parse DTB console for UART information  */
+	if (fdt_get_uart_info(&dt_uart_info) == 0) {
+		if (CONSOLE_IS(dtb)) {
+			boot_hd_console.base = dt_uart_info.base;
+			boot_hd_console.baud_rate = dt_uart_info.baud_rate;
+			boot_hd_console.console_type = dt_uart_info.console_type;
 		}
-	} else if (strncmp(uart_info->compatible, DT_UART_DCC_COMPAT,
-			  strlen(DT_UART_DCC_COMPAT)) == 0) {
-		rc = console_dcc_register();
-		if (rc == 0) {
-			panic();
-		}
-		console_boot_end(bl31_boot_console);
 	} else {
-		WARN("BL31: No console device found in DT.\n");
+		ERROR("Failed to initialize DT console or console node is disabled\n");
 	}
-
-error:
-	return rc;
-}
 #endif
 
-void setup_console(void)
-{
-	int32_t rc;
-	uint32_t uart_clk = get_uart_clk();
+	/* Initialize the boot console */
+	register_console(&boot_hd_console, &boot_console);
 
-#if defined(PLAT_zynqmp)
-	if (CONSOLE_IS(cadence) || (CONSOLE_IS(cadence1))) {
-		rc = console_cdns_register(UART_BASE,
-					   uart_clk,
-					   UART_BAUDRATE,
-					   &console);
-		if (rc == 0) {
-			panic();
-		}
+	INFO("BL31: Early console setup\n");
 
-		console_set_scope(&console, CONSOLE_FLAG_BOOT |
-				  CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
-	}
+#ifdef CONSOLE_RUNTIME
+#if (RT_CONSOLE_IS(dtb) && defined(XILINX_OF_BOARD_DTB_ADDR)) && \
+	       (!defined(PLAT_zynqmp) || (defined(PLAT_zynqmp) && \
+					!IS_TFA_IN_OCM(BL31_BASE)))
+	rt_hd_console.base = dt_uart_info.base;
+	rt_hd_console.baud_rate = dt_uart_info.baud_rate;
+	rt_hd_console.console_type = dt_uart_info.console_type;
 #else
-	if (CONSOLE_IS(pl011) || (CONSOLE_IS(pl011_1))) {
-		/* Initialize the console to provide early debug support */
-		rc = console_pl011_register((uint32_t)UART_BASE,
-					   uart_clk,
-					   (uint32_t)UART_BAUDRATE,
-					   &console);
-		if (rc == 0) {
-			panic();
-		}
-
-		console_set_scope(&console, CONSOLE_FLAG_BOOT |
-				  CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
-	}
+	rt_hd_console.base = (uintptr_t)RT_UART_BASE;
+	rt_hd_console.baud_rate = (uint32_t)UART_BAUDRATE;
+	rt_hd_console.console_type = RT_UART_TYPE;
 #endif
-	if (CONSOLE_IS(dcc)) {
-		/* Initialize the dcc console for debug */
-		rc = console_dcc_register();
-		if (rc == 0) {
-			panic();
-		}
-	}
-	INFO("BL31: Early console setup\n");
 
-#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
-	static dt_uart_info_t uart_info = {0};
+	if ((rt_hd_console.console_type == boot_hd_console.console_type) &&
+			(rt_hd_console.base == boot_hd_console.base)) {
+		console_set_scope(&boot_console,
+				CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | CONSOLE_FLAG_RUNTIME);
+		INFO("Successfully initialized runtime console\n");
+	} else {
+		rt_hd_console.clk = get_uart_clk();
+		rt_hd_console.console_scope = CONSOLE_FLAG_RUNTIME;
 
-	/* Initialize the runtime console using UART information from the DTB */
-	rc = runtime_console_init(&uart_info, &console, uart_clk);
-	if (rc < 0) {
-		ERROR("Failed to initialize runtime console: %d\n", rc);
+		register_console(&rt_hd_console, &runtime_console);
+		INFO("Successfully initialized new runtime console\n");
 	}
 #endif
 }
+#else
+void setup_console(void)
+{
+}
+#endif
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
index c50df7e..3a1c127 100644
--- a/plat/xilinx/versal/include/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -18,13 +18,24 @@
 /* number of interrupt handlers. increase as required */
 #define MAX_INTR_EL3			2
 /* List all consoles */
+#define VERSAL_CONSOLE_ID_none		0
 #define VERSAL_CONSOLE_ID_pl011	1
 #define VERSAL_CONSOLE_ID_pl011_0	1
 #define VERSAL_CONSOLE_ID_pl011_1	2
 #define VERSAL_CONSOLE_ID_dcc		3
+#define VERSAL_CONSOLE_ID_dtb		4
 
 #define CONSOLE_IS(con)	(VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE)
 
+/* Runtime console */
+#define RT_CONSOLE_ID_pl011	1
+#define RT_CONSOLE_ID_pl011_0	1
+#define RT_CONSOLE_ID_pl011_1	2
+#define RT_CONSOLE_ID_dcc	3
+#define RT_CONSOLE_ID_dtb	4
+
+#define RT_CONSOLE_IS(con)	(RT_CONSOLE_ID_ ## con == CONSOLE_RUNTIME)
+
 /* List of platforms */
 #define VERSAL_SILICON              U(0)
 #define VERSAL_SPP                  U(1)
@@ -63,14 +74,37 @@
 #define VERSAL_UART0_BASE		0xFF000000
 #define VERSAL_UART1_BASE		0xFF010000
 
-#if CONSOLE_IS(pl011) || CONSOLE_IS(dcc)
+#if CONSOLE_IS(pl011) || CONSOLE_IS(dtb)
 # define UART_BASE	VERSAL_UART0_BASE
+# define UART_TYPE	CONSOLE_PL011
 #elif CONSOLE_IS(pl011_1)
 # define UART_BASE	VERSAL_UART1_BASE
+# define UART_TYPE	CONSOLE_PL011
+#elif CONSOLE_IS(dcc)
+# define UART_BASE	0x0
+# define UART_TYPE	CONSOLE_DCC
+#elif CONSOLE_IS(none)
+# define UART_TYPE	CONSOLE_NONE
 #else
 # error "invalid VERSAL_CONSOLE"
 #endif
 
+/* Runtime console */
+#if defined(CONSOLE_RUNTIME)
+#if RT_CONSOLE_IS(pl011) || RT_CONSOLE_IS(dtb)
+# define RT_UART_BASE VERSAL_UART0_BASE
+# define RT_UART_TYPE	CONSOLE_PL011
+#elif RT_CONSOLE_IS(pl011_1)
+# define RT_UART_BASE VERSAL_UART1_BASE
+# define RT_UART_TYPE	CONSOLE_PL011
+#elif RT_CONSOLE_IS(dcc)
+# define RT_UART_BASE	0x0
+# define RT_UART_TYPE	CONSOLE_DCC
+#else
+# error "invalid CONSOLE_RUNTIME"
+#endif
+#endif
+
 /*******************************************************************************
  * Platform related constants
  ******************************************************************************/
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index 74c5bf3..a299d14 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -250,7 +250,7 @@
 
 	uint32_t pstate = psci_get_pstate_type(power_state);
 
-	assert(req_state);
+	assert(req_state != NULL);
 
 	/* Sanity check the requested state */
 	if (pstate == PSTATE_TYPE_STANDBY) {
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
index e65800e..7c15be0 100644
--- a/plat/xilinx/versal/platform.mk
+++ b/plat/xilinx/versal/platform.mk
@@ -85,13 +85,27 @@
 				${XLAT_TABLES_LIB_SRCS}
 
 VERSAL_CONSOLE	?=	pl011
-ifeq (${VERSAL_CONSOLE}, $(filter ${VERSAL_CONSOLE},pl011 pl011_0 pl011_1 dcc))
+ifeq (${VERSAL_CONSOLE}, $(filter ${VERSAL_CONSOLE},pl011 pl011_0 pl011_1 dcc dtb none))
 else
   $(error "Please define VERSAL_CONSOLE")
 endif
 
 $(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
 
+# Runtime console in default console in DEBUG build
+ifeq ($(DEBUG), 1)
+CONSOLE_RUNTIME ?= pl011
+endif
+
+# Runtime console
+ifdef CONSOLE_RUNTIME
+ifeq (${CONSOLE_RUNTIME}, $(filter ${CONSOLE_RUNTIME},pl011 pl011_0 pl011_1 dcc dtb))
+$(eval $(call add_define_val,CONSOLE_RUNTIME,RT_CONSOLE_ID_${CONSOLE_RUNTIME}))
+else
+$(error "Please define CONSOLE_RUNTIME")
+endif
+endif
+
 BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
 				lib/cpus/aarch64/cortex_a72.S			\
 				common/fdt_wrappers.c                           \
diff --git a/plat/xilinx/versal_net/include/versal_net_def.h b/plat/xilinx/versal_net/include/versal_net_def.h
index e7d234b..5caf376 100644
--- a/plat/xilinx/versal_net/include/versal_net_def.h
+++ b/plat/xilinx/versal_net/include/versal_net_def.h
@@ -15,13 +15,24 @@
 #define MAX_INTR_EL3			2
 
 /* List all consoles */
+#define VERSAL_NET_CONSOLE_ID_none	U(0)
 #define VERSAL_NET_CONSOLE_ID_pl011	U(1)
 #define VERSAL_NET_CONSOLE_ID_pl011_0	U(1)
 #define VERSAL_NET_CONSOLE_ID_pl011_1	U(2)
 #define VERSAL_NET_CONSOLE_ID_dcc	U(3)
+#define VERSAL_NET_CONSOLE_ID_dtb	U(4)
 
 #define CONSOLE_IS(con)	(VERSAL_NET_CONSOLE_ID_ ## con == VERSAL_NET_CONSOLE)
 
+/* Runtime console */
+#define RT_CONSOLE_ID_pl011    1
+#define RT_CONSOLE_ID_pl011_0  1
+#define RT_CONSOLE_ID_pl011_1  2
+#define RT_CONSOLE_ID_dcc      3
+#define RT_CONSOLE_ID_dtb      4
+
+#define RT_CONSOLE_IS(con)     (RT_CONSOLE_ID_ ## con == CONSOLE_RUNTIME)
+
 /* List all platforms */
 #define VERSAL_NET_SILICON		U(0)
 #define VERSAL_NET_SPP			U(1)
@@ -138,11 +149,35 @@
 
 #define UART_BAUDRATE	115200
 
-#if CONSOLE_IS(pl011_1)
-#define UART_BASE		VERSAL_NET_UART1_BASE
+#if CONSOLE_IS(pl011) || CONSOLE_IS(dtb)
+#define UART_BASE		VERSAL_NET_UART0_BASE
+# define UART_TYPE	CONSOLE_PL011
+#elif CONSOLE_IS(pl011_1)
+#define UART_BASE            VERSAL_NET_UART1_BASE
+# define UART_TYPE	CONSOLE_PL011
+#elif CONSOLE_IS(dcc)
+# define UART_BASE	0x0
+# define UART_TYPE	CONSOLE_DCC
+#elif CONSOLE_IS(none)
+# define UART_TYPE	CONSOLE_NONE
+#else
+# error "invalid VERSAL_NET_CONSOLE"
+#endif
+
+/* Runtime console */
+#if defined(CONSOLE_RUNTIME)
+#if RT_CONSOLE_IS(pl011) || RT_CONSOLE_IS(dtb)
+# define RT_UART_BASE VERSAL_NET_UART0_BASE
+# define RT_UART_TYPE	CONSOLE_PL011
+#elif RT_CONSOLE_IS(pl011_1)
+# define RT_UART_BASE VERSAL_NET_UART1_BASE
+# define RT_UART_TYPE	CONSOLE_PL011
+#elif RT_CONSOLE_IS(dcc)
+# define RT_UART_BASE	0x0
+# define RT_UART_TYPE	CONSOLE_DCC
 #else
-/* Default console is UART0 */
-#define UART_BASE            VERSAL_NET_UART0_BASE
+# error "invalid CONSOLE_RUNTIME"
+#endif
 #endif
 
 /* Processor core device IDs */
diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c
index fb2005d..7a653d4 100644
--- a/plat/xilinx/versal_net/plat_psci_pm.c
+++ b/plat/xilinx/versal_net/plat_psci_pm.c
@@ -247,7 +247,7 @@
 
 	int32_t pstate = psci_get_pstate_type(power_state);
 
-	assert(req_state);
+	assert(req_state != NULL);
 
 	/* Sanity check the requested state */
 	if (pstate == PSTATE_TYPE_STANDBY) {
diff --git a/plat/xilinx/versal_net/platform.mk b/plat/xilinx/versal_net/platform.mk
index 40e9206..9534118 100644
--- a/plat/xilinx/versal_net/platform.mk
+++ b/plat/xilinx/versal_net/platform.mk
@@ -60,7 +60,7 @@
 HW_ASSISTED_COHERENCY := 1
 
 VERSAL_NET_CONSOLE	?=	pl011
-ifeq (${VERSAL_NET_CONSOLE}, $(filter ${VERSAL_NET_CONSOLE},pl011 pl011_0 pl011_1 dcc))
+ifeq (${VERSAL_NET_CONSOLE}, $(filter ${VERSAL_NET_CONSOLE},pl011 pl011_0 pl011_1 dcc dtb none))
 else
   $(error Please define VERSAL_NET_CONSOLE)
 endif
@@ -71,6 +71,20 @@
 $(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
 endif
 
+# Runtime console in default console in DEBUG build
+ifeq ($(DEBUG), 1)
+CONSOLE_RUNTIME ?= pl011
+endif
+
+# Runtime console
+ifdef CONSOLE_RUNTIME
+ifeq (${CONSOLE_RUNTIME}, $(filter ${CONSOLE_RUNTIME},pl011 pl011_0 pl011_1 dcc dtb))
+$(eval $(call add_define_val,CONSOLE_RUNTIME,RT_CONSOLE_ID_${CONSOLE_RUNTIME}))
+else
+$(error "Please define CONSOLE_RUNTIME")
+endif
+endif
+
 # enable assert() for release/debug builds
 ENABLE_ASSERTIONS := 1
 
diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h
index d715ce2..68485cf 100644
--- a/plat/xilinx/zynqmp/include/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/include/zynqmp_def.h
@@ -10,13 +10,24 @@
 #include <plat/arm/common/smccc_def.h>
 #include <plat/common/common_def.h>
 
+#define ZYNQMP_CONSOLE_ID_none		0
 #define ZYNQMP_CONSOLE_ID_cadence	1
 #define ZYNQMP_CONSOLE_ID_cadence0	1
 #define ZYNQMP_CONSOLE_ID_cadence1	2
 #define ZYNQMP_CONSOLE_ID_dcc		3
+#define ZYNQMP_CONSOLE_ID_dtb		4
 
 #define CONSOLE_IS(con)	(ZYNQMP_CONSOLE_ID_ ## con == ZYNQMP_CONSOLE)
 
+/* Runtime console */
+#define RT_CONSOLE_ID_cadence	1
+#define RT_CONSOLE_ID_cadence0	1
+#define RT_CONSOLE_ID_cadence1	2
+#define RT_CONSOLE_ID_dcc	3
+#define RT_CONSOLE_ID_dtb	4
+
+#define RT_CONSOLE_IS(con)	(RT_CONSOLE_ID_ ## con == CONSOLE_RUNTIME)
+
 /* Default counter frequency */
 #define ZYNQMP_DEFAULT_COUNTER_FREQ	0U
 
@@ -144,14 +155,38 @@
 #define ZYNQMP_UART0_BASE		U(0xFF000000)
 #define ZYNQMP_UART1_BASE		U(0xFF010000)
 
-#if CONSOLE_IS(cadence) || CONSOLE_IS(dcc)
+/* Boot console */
+#if CONSOLE_IS(cadence) || CONSOLE_IS(dtb)
 # define UART_BASE	ZYNQMP_UART0_BASE
+# define UART_TYPE	CONSOLE_CDNS
 #elif CONSOLE_IS(cadence1)
 # define UART_BASE	ZYNQMP_UART1_BASE
+# define UART_TYPE	CONSOLE_CDNS
+#elif CONSOLE_IS(dcc)
+# define UART_BASE	0x0
+# define UART_TYPE	CONSOLE_DCC
+#elif CONSOLE_IS(none)
+# define UART_TYPE	CONSOLE_NONE
 #else
 # error "invalid ZYNQMP_CONSOLE"
 #endif
 
+/* Runtime console */
+#if defined(CONSOLE_RUNTIME)
+#if RT_CONSOLE_IS(cadence) || RT_CONSOLE_IS(dtb)
+# define RT_UART_BASE	ZYNQMP_UART0_BASE
+# define RT_UART_TYPE	CONSOLE_CDNS
+#elif RT_CONSOLE_IS(cadence1)
+# define RT_UART_BASE	ZYNQMP_UART1_BASE
+# define RT_UART_TYPE	CONSOLE_CDNS
+#elif RT_CONSOLE_IS(dcc)
+# define RT_UART_BASE	0x0
+# define RT_UART_TYPE	CONSOLE_DCC
+#else
+# error "invalid CONSOLE_RUNTIME"
+#endif
+#endif
+
 /* Must be non zero */
 #define UART_BAUDRATE		115200
 
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index 9fdc649..5a86658 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -111,12 +111,26 @@
 				${XLAT_TABLES_LIB_SRCS}
 
 ZYNQMP_CONSOLE	?=	cadence
-ifeq (${ZYNQMP_CONSOLE}, $(filter ${ZYNQMP_CONSOLE},cadence cadence0 cadence1 dcc))
+ifeq (${ZYNQMP_CONSOLE}, $(filter ${ZYNQMP_CONSOLE},cadence cadence0 cadence1 dcc dtb none))
 else
   $(error "Please define ZYNQMP_CONSOLE")
 endif
 $(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}))
 
+# Runtime console in default console in DEBUG build
+ifeq ($(DEBUG), 1)
+CONSOLE_RUNTIME ?= cadence
+endif
+
+# Runtime console
+ifdef CONSOLE_RUNTIME
+ifeq (${CONSOLE_RUNTIME}, $(filter ${CONSOLE_RUNTIME},cadence cadence0 cadence1 dcc dtb))
+$(eval $(call add_define_val,CONSOLE_RUNTIME,RT_CONSOLE_ID_${CONSOLE_RUNTIME}))
+else
+$(error "Please define CONSOLE_RUNTIME")
+endif
+endif
+
 # Build PM code as a Library
 include plat/xilinx/zynqmp/libpm.mk
 
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
index 9682e59..5a1e218 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -2791,7 +2791,7 @@
 {
 	struct pm_pll *pll = pm_clock_get_pll(clock_id);
 
-	if (pll) {
+	if (pll != NULL) {
 		*node_id = pll->nid;
 		return PM_RET_SUCCESS;
 	}
@@ -2883,7 +2883,7 @@
 	enum pm_ret_status status;
 	enum pm_pll_mode mode;
 
-	if ((pll == NULL) || !state) {
+	if ((pll == NULL) || (state == NULL)) {
 		return PM_RET_ERROR_ARGS;
 	}
 
@@ -3013,7 +3013,7 @@
 {
 	struct pm_pll *pll = pm_clock_get_pll(clock_id);
 
-	if ((pll == NULL) || !mode) {
+	if ((pll == NULL) || (mode == NULL)) {
 		return PM_RET_ERROR_ARGS;
 	}
 	*mode = pll->mode;
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
index daf3e61..d7c9f24 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
@@ -1150,7 +1150,7 @@
 
 	/* First try to handle it as a PLL */
 	pll = pm_clock_get_pll(clock_id);
-	if (pll) {
+	if (pll != NULL) {
 		return pm_clock_pll_enable(pll);
 	}
 
@@ -1175,7 +1175,7 @@
 
 	/* First try to handle it as a PLL */
 	pll = pm_clock_get_pll(clock_id);
-	if (pll) {
+	if (pll != NULL) {
 		return pm_clock_pll_disable(pll);
 	}
 
@@ -1203,9 +1203,9 @@
 
 	/* First try to handle it as a PLL */
 	pll = pm_clock_get_pll(clock_id);
-	if (pll)
+	if (pll != NULL) {
 		return pm_clock_pll_get_state(pll, state);
-
+	}
 	/* Check if clock ID is a valid on-chip clock */
 	status = pm_clock_id_is_valid(clock_id);
 	if (status != PM_RET_SUCCESS) {
@@ -1341,7 +1341,7 @@
 
 	/* First try to handle it as a PLL */
 	pll = pm_clock_get_pll_by_related_clk(clock_id);
-	if (pll) {
+	if (pll != NULL) {
 		return pm_clock_pll_set_parent(pll, clock_id, parent_index);
 	}
 
@@ -1376,7 +1376,7 @@
 
 	/* First try to handle it as a PLL */
 	pll = pm_clock_get_pll_by_related_clk(clock_id);
-	if (pll) {
+	if (pll != NULL) {
 		return pm_clock_pll_get_parent(pll, clock_id, parent_index);
 	}
 
diff --git a/services/std_svc/rmmd/rmmd_attest.c b/services/std_svc/rmmd/rmmd_attest.c
index f73236c..7d4ea70 100644
--- a/services/std_svc/rmmd/rmmd_attest.c
+++ b/services/std_svc/rmmd/rmmd_attest.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,7 +13,8 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 #include "rmmd_private.h"
-#include <services/rmmd_svc.h>
+#include <services/rmm_el3_token_sign.h>
+#include <smccc_helpers.h>
 
 static spinlock_t lock;
 
@@ -156,10 +158,110 @@
 						 (unsigned int)ecc_curve);
 	if (err != 0) {
 		ERROR("Failed to get attestation key: %d.\n", err);
-		err =  E_RMM_UNK;
+		err = E_RMM_UNK;
 	}
 
 	spin_unlock(&lock);
 
 	return err;
 }
+
+static int rmmd_el3_token_sign_push_req(uint64_t buf_pa, uint64_t buf_size)
+{
+	int err;
+
+	err = validate_buffer_params(buf_pa, buf_size);
+	if (err != 0) {
+		return err;
+	}
+
+	if (buf_size < sizeof(struct el3_token_sign_request)) {
+		return E_RMM_INVAL;
+	}
+
+	spin_lock(&lock);
+
+	/* Call platform port to handle attestation toekn signing request. */
+	err = plat_rmmd_el3_token_sign_push_req((struct el3_token_sign_request *)buf_pa);
+
+	spin_unlock(&lock);
+
+	return err;
+}
+
+static int rmmd_el3_token_sign_pull_resp(uint64_t buf_pa, uint64_t buf_size)
+{
+	int err;
+
+	err = validate_buffer_params(buf_pa, buf_size);
+	if (err != 0) {
+		return err;
+	}
+
+
+	if (buf_size < sizeof(struct el3_token_sign_response)) {
+		return E_RMM_INVAL;
+	}
+
+	spin_lock(&lock);
+
+	/* Pull attestation signing response from HES. */
+	err = plat_rmmd_el3_token_sign_pull_resp(
+			(struct el3_token_sign_response *)buf_pa);
+
+	spin_unlock(&lock);
+
+	return err;
+}
+
+static int rmmd_attest_get_attest_pub_key(uint64_t buf_pa, uint64_t *buf_size,
+				   uint64_t ecc_curve)
+{
+	int err;
+
+	err = validate_buffer_params(buf_pa, *buf_size);
+	if (err != 0) {
+		return err;
+	}
+
+	if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) {
+		ERROR("Invalid ECC curve specified\n");
+		return E_RMM_INVAL;
+	}
+
+	spin_lock(&lock);
+
+	/* Get the Realm attestation public key from platform port. */
+	err = plat_rmmd_el3_token_sign_get_rak_pub(
+		(uintptr_t)buf_pa, buf_size, (unsigned int)ecc_curve);
+
+	spin_unlock(&lock);
+	if (err != 0) {
+		ERROR("Failed to get attestation public key from HES: %d.\n",
+		      err);
+		err = E_RMM_UNK;
+	}
+
+
+	return err;
+}
+
+uint64_t rmmd_el3_token_sign(void *handle, uint64_t opcode, uint64_t x2,
+				    uint64_t x3, uint64_t x4)
+{
+	int ret;
+
+	switch (opcode) {
+	case RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP:
+		ret = rmmd_el3_token_sign_push_req(x2, x3);
+		SMC_RET1(handle, ret);
+	case RMM_EL3_TOKEN_SIGN_PULL_RESP_OP:
+		ret = rmmd_el3_token_sign_pull_resp(x2, x3);
+		SMC_RET1(handle, ret);
+	case RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP:
+		ret = rmmd_attest_get_attest_pub_key(x2, &x3, x4);
+		SMC_RET2(handle, ret, x3);
+	default:
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index 153bb01..d063ea3 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -441,6 +441,21 @@
 	return ret;
 }
 
+static int rmm_el3_ifc_get_feat_register(uint64_t feat_reg_idx,
+					 uint64_t *feat_reg)
+{
+	if (feat_reg_idx != RMM_EL3_FEAT_REG_0_IDX) {
+		ERROR("RMMD: Failed to get feature register %ld\n", feat_reg_idx);
+		return E_RMM_INVAL;
+	}
+
+	*feat_reg = 0UL;
+#if RMMD_ENABLE_EL3_TOKEN_SIGN
+	*feat_reg |= RMM_EL3_FEAT_REG_0_EL3_TOKEN_SIGN_MASK;
+#endif
+	return E_RMM_OK;
+}
+
 /*******************************************************************************
  * This function handles RMM-EL3 interface SMCs
  ******************************************************************************/
@@ -448,7 +463,7 @@
 				uint64_t x3, uint64_t x4, void *cookie,
 				void *handle, uint64_t flags)
 {
-	uint64_t remaining_len = 0;
+	uint64_t remaining_len = 0UL;
 	uint32_t src_sec_state;
 	int ret;
 
@@ -479,7 +494,13 @@
 	case RMM_ATTEST_GET_REALM_KEY:
 		ret = rmmd_attest_get_signing_key(x1, &x2, x3);
 		SMC_RET2(handle, ret, x2);
-
+	case RMM_EL3_FEATURES:
+		ret = rmm_el3_ifc_get_feat_register(x1, &x2);
+		SMC_RET2(handle, ret, x2);
+#if RMMD_ENABLE_EL3_TOKEN_SIGN
+	case RMM_EL3_TOKEN_SIGN:
+		return rmmd_el3_token_sign(handle, x1, x2, x3, x4);
+#endif
 	case RMM_BOOT_COMPLETE:
 		VERBOSE("RMMD: running rmmd_rmm_sync_exit\n");
 		rmmd_rmm_sync_exit(x1);
diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h
index 6d3b5ec..0ce104d 100644
--- a/services/std_svc/rmmd/rmmd_private.h
+++ b/services/std_svc/rmmd/rmmd_private.h
@@ -51,6 +51,8 @@
 				   uint64_t *remaining_len);
 int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size,
 				uint64_t ecc_curve);
+uint64_t rmmd_el3_token_sign(void *handle, uint64_t x1, uint64_t x2,
+				    uint64_t x3, uint64_t x4);
 
 /* Assembly helpers */
 uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx);