refactor(sgi): move from "sgi" to "neoverse_rd"

Currently, reference design platforms such as RD-N2, RD-N1-Edge,
RD-V1-MC, RD-V1 and SGI-575 utilize "css/sgi" as the common source
directory. The "sgi" prefix originated from the System Guidance for
Infrastructure (SGI) and was initially associated with the SGI-575
platform. However, subsequent platforms released were under the Neoverse
Reference Design product name.

To align with the Neoverse Reference Design nomenclature, rename the
common source directory from "css/sgi" to "css/neoverse_rd" and update
all file prefixes from "sgi" to "nrd."

Signed-off-by: Rohit Mathew <Rohit.Mathew@arm.com>
Change-Id: I3dcbb31b9ab202e82caf25218ba33c520dcea4e4
diff --git a/plat/arm/css/neoverse_rd/aarch64/nrd_helper.S b/plat/arm/css/neoverse_rd/aarch64/nrd_helper.S
new file mode 100644
index 0000000..14c3a7c
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/aarch64/nrd_helper.S
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cortex_a75.h>
+#include <neoverse_n1.h>
+#include <neoverse_v1.h>
+#include <neoverse_n2.h>
+#include <cpu_macros.S>
+
+	.globl	plat_arm_calc_core_pos
+	.globl	plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Helper function to calculate the core position.
+	 * (ChipId * PLAT_ARM_CLUSTER_COUNT *
+	 *  CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
+	 * (ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
+	 * (CPUId * CSS_SGI_MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((((ChipId * PLAT_ARM_CLUSTER_COUNT) + ClusterId) *
+	 *   CSS_SGI_MAX_CPUS_PER_CLUSTER) + CPUId) * CSS_SGI_MAX_PE_PER_CPU +
+	 * ThreadId
+	 * ------------------------------------------------------
+	 */
+
+func plat_arm_calc_core_pos
+	mov	x4, x0
+
+	/*
+	 * The MT bit in MPIDR is always set for SGI platforms
+	 * and the affinity level 0 corresponds to thread affinity level.
+	 */
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx    x0, x4, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx    x1, x4, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx    x2, x4, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx    x3, x4, #MPIDR_AFF3_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov     x4, #PLAT_ARM_CLUSTER_COUNT
+	madd    x2, x3, x4, x2
+	mov     x4, #CSS_SGI_MAX_CPUS_PER_CLUSTER
+	madd    x1, x2, x4, x1
+	mov     x4, #CSS_SGI_MAX_PE_PER_CPU
+	madd    x0, x1, x4, x0
+	ret
+endfunc plat_arm_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the CPU MIDR and disable power down bit for
+	 * that CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	jump_if_cpu_midr CORTEX_A75_MIDR, A75
+	jump_if_cpu_midr NEOVERSE_N1_MIDR, N1
+	jump_if_cpu_midr NEOVERSE_V1_MIDR, V1
+	jump_if_cpu_midr NEOVERSE_N2_MIDR, N2
+	ret
+
+	/* -----------------------------------------------------
+	 * Disable CPU power down bit in power control register
+	 * -----------------------------------------------------
+	 */
+A75:
+	mrs	x0, CORTEX_A75_CPUPWRCTLR_EL1
+	bic	x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A75_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+
+N1:
+	mrs	x0, NEOVERSE_N1_CPUPWRCTLR_EL1
+	bic	x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK
+	msr	NEOVERSE_N1_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+
+V1:
+	mrs	x0, NEOVERSE_V1_CPUPWRCTLR_EL1
+	bic	x0, x0, #NEOVERSE_V1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	NEOVERSE_V1_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+
+N2:
+	mrs	x0, NEOVERSE_N2_CPUPWRCTLR_EL1
+	bic	x0, x0, #NEOVERSE_N2_CORE_PWRDN_EN_BIT
+	msr	NEOVERSE_N2_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc plat_reset_handler
diff --git a/plat/arm/css/neoverse_rd/include/nrd_base_platform_def.h b/plat/arm/css/neoverse_rd/include/nrd_base_platform_def.h
new file mode 100644
index 0000000..619f706
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_base_platform_def.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_BASE_PLATFORM_DEF_H
+#define NRD_BASE_PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_CORE_COUNT		(CSS_SGI_CHIP_COUNT *		\
+					PLAT_ARM_CLUSTER_COUNT *	\
+					CSS_SGI_MAX_CPUS_PER_CLUSTER *	\
+					CSS_SGI_MAX_PE_PER_CPU)
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE	0x00080000	/* 512 KB */
+
+/* Remote chip address offset */
+#define CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n)	\
+		((ULL(1) << CSS_SGI_ADDR_BITS_PER_CHIP) * (n))
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage. In addition to that, on
+ * multi-chip platforms, address regions on each of the remote chips are
+ * also mapped. In BL31, for instance, three address regions on the remote
+ * chips are accessed - secure ram, css device and soc device regions.
+ */
+#if defined(IMAGE_BL31)
+# if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
+#  define PLAT_ARM_MMAP_ENTRIES		(10  + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+#  define MAX_XLAT_TABLES		(8  + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+#  define PLAT_SP_IMAGE_MMAP_REGIONS	12
+#  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	14
+# else
+#  define PLAT_ARM_MMAP_ENTRIES		(5 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+#  define MAX_XLAT_TABLES		(6 + ((CSS_SGI_CHIP_COUNT - 1) * 3))
+# endif
+#elif defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		5
+#elif defined(IMAGE_BL2)
+# define PLAT_ARM_MMAP_ENTRIES		(11 + (CSS_SGI_CHIP_COUNT - 1))
+
+/*
+ * MAX_XLAT_TABLES entries need to be doubled because when the address width
+ * exceeds 40 bits an additional level of translation is required. In case of
+ * multichip platforms peripherals also fall into address space with width
+ * > 40 bits
+ *
+ */
+# define MAX_XLAT_TABLES		(7  + ((CSS_SGI_CHIP_COUNT - 1) * 2))
+#elif !USE_ROMLIB
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		7
+#else
+# define PLAT_ARM_MMAP_ENTRIES		12
+# define MAX_XLAT_TABLES		6
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_ARM_MAX_BL1_RW_SIZE	(64 * 1024)	/* 64 KB */
+
+/*
+ * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page
+ */
+
+#if USE_ROMLIB
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	0x1000
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	0xe000
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	0
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	0
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth. Additional 8KiB space is added per chip in
+ * order to accommodate the additional level of translation required for "TZC"
+ * peripheral access which lies in >4TB address space.
+ *
+ */
+#if TRUSTED_BOARD_BOOT
+# define PLAT_ARM_MAX_BL2_SIZE		(0x20000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+							0x2000))
+#else
+# define PLAT_ARM_MAX_BL2_SIZE		(0x14000 + ((CSS_SGI_CHIP_COUNT - 1) * \
+							0x2000))
+#endif
+
+/*
+ * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
+ * calculated using the current BL31 PROGBITS debug size plus the sizes of BL2
+ * and BL1-RW. CSS_SGI_BL31_SIZE - is tuned with respect to the actual BL31
+ * PROGBITS size which is around 64-68KB at the time this change is being made.
+ * A buffer of ~35KB is added to account for future expansion of the image,
+ * making it a total of 100KB.
+ */
+#define CSS_SGI_BL31_SIZE		(116 * 1024)	/* 116 KB */
+#define PLAT_ARM_MAX_BL31_SIZE		(CSS_SGI_BL31_SIZE +		\
+						PLAT_ARM_MAX_BL2_SIZE +	\
+						PLAT_ARM_MAX_BL1_RW_SIZE)
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x440
+# endif
+#elif defined(IMAGE_BL2)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL2U)
+# define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+# if SPM_MM
+#  define PLATFORM_STACK_SIZE 0x500
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/* PL011 UART related constants */
+#define SOC_CSS_SEC_UART_BASE			UL(0x2A410000)
+#define SOC_CSS_NSEC_UART_BASE			UL(0x2A400000)
+#define SOC_CSS_UART_SIZE			UL(0x10000)
+#define SOC_CSS_UART_CLK_IN_HZ			UL(7372800)
+
+/* UART related constants */
+#define PLAT_ARM_BOOT_UART_BASE			SOC_CSS_SEC_UART_BASE
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ		SOC_CSS_UART_CLK_IN_HZ
+
+#define PLAT_ARM_RUN_UART_BASE			SOC_CSS_SEC_UART_BASE
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ		SOC_CSS_UART_CLK_IN_HZ
+
+#define PLAT_ARM_CRASH_UART_BASE		SOC_CSS_SEC_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ		SOC_CSS_UART_CLK_IN_HZ
+
+#define PLAT_ARM_NSTIMER_FRAME_ID	0
+
+#define PLAT_ARM_TRUSTED_ROM_BASE	0x0
+#define PLAT_ARM_TRUSTED_ROM_SIZE	0x00080000	/* 512KB */
+
+#define PLAT_ARM_NSRAM_BASE		0x06000000
+#define PLAT_ARM_NSRAM_SIZE		0x00080000	/* 512KB */
+
+#define PLAT_ARM_DRAM2_BASE		ULL(0x8080000000)
+#define PLAT_ARM_DRAM2_SIZE		ULL(0x180000000)
+
+#define PLAT_ARM_G1S_IRQ_PROPS(grp)	CSS_G1S_IRQ_PROPS(grp)
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+#define CSS_SGI_DEVICE_BASE	(0x20000000)
+#define CSS_SGI_DEVICE_SIZE	(0x20000000)
+#define CSS_SGI_MAP_DEVICE	MAP_REGION_FLAT(		\
+					CSS_SGI_DEVICE_BASE,	\
+					CSS_SGI_DEVICE_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define ARM_MAP_SHARED_RAM_REMOTE_CHIP(n)					\
+			MAP_REGION_FLAT(					\
+				CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) +		\
+				ARM_SHARED_RAM_BASE,				\
+				ARM_SHARED_RAM_SIZE,				\
+				MT_NON_CACHEABLE | MT_RW | MT_SECURE		\
+			)
+
+#define CSS_SGI_MAP_DEVICE_REMOTE_CHIP(n)					\
+			MAP_REGION_FLAT(					\
+				CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) +		\
+				CSS_SGI_DEVICE_BASE,				\
+				CSS_SGI_DEVICE_SIZE,				\
+				MT_DEVICE | MT_RW | MT_SECURE			\
+			)
+
+#define SOC_CSS_MAP_DEVICE_REMOTE_CHIP(n)					\
+			MAP_REGION_FLAT(					\
+				CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) +		\
+				SOC_CSS_DEVICE_BASE,				\
+				SOC_CSS_DEVICE_SIZE,				\
+				MT_DEVICE | MT_RW | MT_SECURE			\
+			)
+
+/* Map the secure region for access from S-EL0 */
+#define PLAT_ARM_SECURE_MAP_DEVICE	MAP_REGION_FLAT(	\
+					SOC_CSS_DEVICE_BASE,	\
+					SOC_CSS_DEVICE_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
+
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
+#define PLAT_SP_PRI				PLAT_RAS_PRI
+#else
+#define PLAT_SP_PRI				0x10
+#endif
+
+#if (SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)) && ENABLE_FEAT_RAS && FFH_SUPPORT
+/*
+ * CPER buffer memory of 128KB is reserved and it is placed adjacent to the
+ * memory shared between EL3 and S-EL0.
+ */
+#define CSS_SGI_SP_CPER_BUF_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE + \
+					 PLAT_SP_IMAGE_NS_BUF_SIZE)
+#define CSS_SGI_SP_CPER_BUF_SIZE	ULL(0x10000)
+#define CSS_SGI_SP_CPER_BUF_MMAP	MAP_REGION2(			       \
+						CSS_SGI_SP_CPER_BUF_BASE,      \
+						CSS_SGI_SP_CPER_BUF_BASE,      \
+						CSS_SGI_SP_CPER_BUF_SIZE,      \
+						MT_RW_DATA | MT_NS | MT_USER,  \
+						PAGE_SIZE)
+
+/*
+ * Secure partition stack follows right after the memory space reserved for
+ * CPER buffer memory.
+ */
+#define PLAT_ARM_SP_IMAGE_STACK_BASE		(PLAT_SP_IMAGE_NS_BUF_BASE +   \
+						 PLAT_SP_IMAGE_NS_BUF_SIZE +   \
+						 CSS_SGI_SP_CPER_BUF_SIZE)
+#elif (SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP))
+/*
+ * Secure partition stack follows right after the memory region that is shared
+ * between EL3 and S-EL0.
+ */
+#define PLAT_ARM_SP_IMAGE_STACK_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE +	\
+					 PLAT_SP_IMAGE_NS_BUF_SIZE)
+#endif /* SPM_MM && ENABLE_FEAT_RAS && FFH_SUPPORT */
+
+/* Platform ID address */
+#define SSC_VERSION                     (SSC_REG_BASE + SSC_VERSION_OFFSET)
+#ifndef __ASSEMBLER__
+/* SSC_VERSION related accessors */
+/* Returns the part number of the platform */
+#define GET_SGI_PART_NUM                                       \
+		GET_SSC_VERSION_PART_NUM(mmio_read_32(SSC_VERSION))
+/* Returns the configuration number of the platform */
+#define GET_SGI_CONFIG_NUM                                     \
+		GET_SSC_VERSION_CONFIG(mmio_read_32(SSC_VERSION))
+#endif /* __ASSEMBLER__ */
+
+/*******************************************************************************
+ * Memprotect definitions
+ ******************************************************************************/
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*Secure Watchdog Constants */
+#define SBSA_SECURE_WDOG_BASE		UL(0x2A480000)
+#define SBSA_SECURE_WDOG_TIMEOUT	UL(100)
+
+/* Number of SCMI channels on the platform */
+#define PLAT_ARM_SCMI_CHANNEL_COUNT	CSS_SGI_CHIP_COUNT
+
+/*
+ * Mapping definition of the TrustZone Controller for ARM SGI/RD platforms
+ * where both the DRAM regions are marked for non-secure access. This applies
+ * to multi-chip platforms.
+ */
+#define SGI_PLAT_TZC_NS_REMOTE_REGIONS_DEF(n)				\
+	{CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_BASE,		\
+		CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM1_END,	\
+		ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS},	\
+	{CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_BASE,		\
+		CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + ARM_DRAM2_END,	\
+		ARM_TZC_NS_DRAM_S_ACCESS, PLAT_ARM_TZC_NS_DEV_ACCESS}
+
+#if SPM_MM
+
+/*
+ * Stand-alone MM logs would be routed via secure UART. Define page table
+ * entry for secure UART which would be common to all platforms.
+ */
+#define SOC_PLATFORM_SECURE_UART	MAP_REGION_FLAT(		\
+					SOC_CSS_SEC_UART_BASE,		\
+					SOC_CSS_UART_SIZE,		\
+					MT_DEVICE | MT_RW | 		\
+					MT_SECURE | MT_USER)
+
+#endif
+
+/* Index of SDS region used in the communication with SCP */
+#define SDS_SCP_AP_REGION_ID			U(0)
+/* SDS ID for unusable CPU MPID list structure */
+#define SDS_ISOLATED_CPU_LIST_ID		U(128)
+
+#endif /* NRD_BASE_PLATFORM_DEF_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_dmc620_tzc_regions.h b/plat/arm/css/neoverse_rd/include/nrd_dmc620_tzc_regions.h
new file mode 100644
index 0000000..a38c759
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_dmc620_tzc_regions.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_DMC620_TZC_REGIONS_H
+#define NRD_DMC620_TZC_REGIONS_H
+
+#include <drivers/arm/tzc_dmc620.h>
+
+#if SPM_MM
+#define CSS_SGI_DMC620_TZC_REGIONS_DEF				\
+	{							\
+		.region_base = ARM_AP_TZC_DRAM1_BASE,		\
+		.region_top = PLAT_SP_IMAGE_NS_BUF_BASE - 1,	\
+		.sec_attr = TZC_DMC620_REGION_S_RDWR		\
+	}, {							\
+		.region_base = PLAT_SP_IMAGE_NS_BUF_BASE,	\
+		.region_top = PLAT_ARM_SP_IMAGE_STACK_BASE - 1,	\
+		.sec_attr = TZC_DMC620_REGION_S_NS_RDWR		\
+	}, {							\
+		.region_base = PLAT_ARM_SP_IMAGE_STACK_BASE,	\
+		.region_top = ARM_AP_TZC_DRAM1_END,		\
+		.sec_attr = TZC_DMC620_REGION_S_RDWR		\
+	}
+#else
+#define CSS_SGI_DMC620_TZC_REGIONS_DEF				\
+	{							\
+		.region_base = ARM_AP_TZC_DRAM1_BASE,		\
+		.region_top = ARM_AP_TZC_DRAM1_END,		\
+		.sec_attr = TZC_DMC620_REGION_S_RDWR		\
+	}
+#endif /* SPM_MM */
+
+#endif /* NRD_DMC620_TZC_REGIONS_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_plat.h b/plat/arm/css/neoverse_rd/include/nrd_plat.h
new file mode 100644
index 0000000..d5bfb60
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_plat.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_PLAT_H
+#define NRD_PLAT_H
+
+/* BL31 platform setup common to all SGI based platforms */
+void sgi_bl31_common_platform_setup(void);
+
+#endif /* NRD_PLAT_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_ras.h b/plat/arm/css/neoverse_rd/include/nrd_ras.h
new file mode 100644
index 0000000..e5c3f2c
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_ras.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_RAS_H
+#define NRD_RAS_H
+
+#include <lib/extensions/ras.h>
+#include <plat/common/platform.h>
+
+/*
+ * Interrupt type supported.
+ * - SGI_RAS_INTR_TYPE_SPI: Denotes a SPI interrupt
+ * - SGI_RAS_INTR_TYPE_PPI: Denotes a PPI interrupt
+ */
+#define SGI_RAS_INTR_TYPE_SPI 0
+#define SGI_RAS_INTR_TYPE_PPI 1
+
+/*
+ * MM Communicate information structure. Required to generate MM Communicate
+ * payload to be shared with Standalone MM.
+ */
+typedef struct mm_communicate_header {
+	struct efi_guid	header_guid;
+	size_t		message_len;
+	uint8_t		data[1];
+} mm_communicate_header_t;
+
+/* RAS error info data structure. */
+struct sgi_ras_ev_map {
+	int sdei_ev_num;	/* SDEI Event number */
+	int intr;		/* Physical intr number */
+	int intr_type;          /* Interrupt Type (SPI or PPI)*/
+};
+
+/* RAS config data structure. Must be defined by each platform. */
+struct plat_sgi_ras_config {
+	struct sgi_ras_ev_map *ev_map;
+	int ev_map_size;
+};
+
+/*
+ * Find event map for a given interrupt number. On success, returns pointer
+ * to the event map. On error, returns NULL.
+ */
+struct sgi_ras_ev_map *sgi_find_ras_event_map_by_intr(uint32_t intr_num);
+
+/*
+ * Initialization function for the framework.
+ *
+ * Registers RAS config provided by the platform and then configures and
+ * enables interrupt for each registered error. On success, return 0.
+ */
+int sgi_ras_platform_setup(struct plat_sgi_ras_config *config);
+
+/* Base element RAM RAS interrupt handler function. */
+int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec,
+				int probe_data,
+				const struct err_handler_data *const data);
+
+/* CPU RAS interrupt handler */
+int sgi_ras_cpu_intr_handler(const struct err_record_info *err_rec,
+				int probe_data,
+				const struct err_handler_data *const data);
+
+#endif /* NRD_RAS_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_sdei.h b/plat/arm/css/neoverse_rd/include/nrd_sdei.h
new file mode 100644
index 0000000..81bd513
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_sdei.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_SDEI_H
+#define NRD_SDEI_H
+
+#if SDEI_SUPPORT
+
+/* ARM SDEI dynamic shared event numbers */
+#define SGI_SDEI_DS_EVENT_0		U(804)
+#define SGI_SDEI_DS_EVENT_1		U(805)
+
+#define PLAT_ARM_PRIVATE_SDEI_EVENTS					      \
+		SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI),			      \
+		SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_0, SDEI_MAPF_CRITICAL), \
+		SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_1, SDEI_MAPF_CRITICAL),
+
+#define PLAT_ARM_SHARED_SDEI_EVENTS
+
+#endif /* SDEI_SUPPORT */
+
+#endif /* NRD_SDEI_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_soc_css_def.h b/plat/arm/css/neoverse_rd/include/nrd_soc_css_def.h
new file mode 100644
index 0000000..7c1f5ae
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_soc_css_def.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_SOC_CSS_DEF_H
+#define NRD_SOC_CSS_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * Definitions common to all ARM CSSv1-based development platforms
+ */
+
+/* Platform ID address */
+#define BOARD_CSS_PLAT_ID_REG_ADDR		UL(0x7ffe00e0)
+
+/* Platform ID related accessors */
+#define BOARD_CSS_PLAT_ID_REG_ID_MASK		0x0f
+#define BOARD_CSS_PLAT_ID_REG_ID_SHIFT		0x0
+#define BOARD_CSS_PLAT_TYPE_EMULATOR		0x02
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+
+#define BOARD_CSS_GET_PLAT_TYPE(addr)					\
+	((mmio_read_32(addr) & BOARD_CSS_PLAT_ID_REG_ID_MASK)		\
+	>> BOARD_CSS_PLAT_ID_REG_ID_SHIFT)
+
+#endif /* __ASSEMBLER__ */
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FLASH_IMAGE_BASE	V2M_FLASH0_BASE
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE	(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#endif /* NRD_SOC_CSS_DEF_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_soc_css_def_v2.h b/plat/arm/css/neoverse_rd/include/nrd_soc_css_def_v2.h
new file mode 100644
index 0000000..81cbdf4
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_soc_css_def_v2.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_SOC_CSS_DEF_V2_H
+#define NRD_SOC_CSS_DEF_V2_H
+
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * Definitions common to all ARM CSS SoCs
+ */
+
+/* Following covers ARM CSS SoC Peripherals */
+
+#define SOC_SYSTEM_PERIPH_BASE		UL(0x0C000000)
+#define SOC_SYSTEM_PERIPH_SIZE		UL(0x02000000)
+
+#define SOC_PLATFORM_PERIPH_BASE	UL(0x0E000000)
+#define SOC_PLATFORM_PERIPH_SIZE	UL(0x02000000)
+
+#define SOC_CSS_PCIE_CONTROL_BASE	UL(0x0ef20000)
+
+/* Memory controller */
+#define SOC_MEMCNTRL_BASE		UL(0x10000000)
+#define SOC_MEMCNTRL_SIZE		UL(0x10000000)
+
+/* SoC NIC-400 Global Programmers View (GPV) */
+#define SOC_CSS_NIC400_BASE		UL(0x0ED00000)
+
+#define SOC_CSS_NIC400_USB_EHCI		U(0)
+#define SOC_CSS_NIC400_TLX_MASTER	U(1)
+#define SOC_CSS_NIC400_USB_OHCI		U(2)
+#define SOC_CSS_NIC400_PL354_SMC	U(3)
+/*
+ * The apb4_bridge controls access to:
+ *   - the PCIe configuration registers
+ *   - the MMU units for USB, HDLCD and DMA
+ */
+#define SOC_CSS_NIC400_APB4_BRIDGE	U(4)
+
+/* Non-volatile counters */
+#define SOC_TRUSTED_NVCTR_BASE		UL(0x0EE70000)
+#define TFW_NVCTR_BASE			(SOC_TRUSTED_NVCTR_BASE + 0x0000)
+#define TFW_NVCTR_SIZE			U(4)
+#define NTFW_CTR_BASE			(SOC_TRUSTED_NVCTR_BASE + 0x0004)
+#define NTFW_CTR_SIZE			U(4)
+
+/* Keys */
+#define SOC_KEYS_BASE			UL(0x0EE80000)
+#define TZ_PUB_KEY_HASH_BASE		(SOC_KEYS_BASE + 0x0000)
+#define TZ_PUB_KEY_HASH_SIZE		U(32)
+#define HU_KEY_BASE			(SOC_KEYS_BASE + 0x0020)
+#define HU_KEY_SIZE			U(16)
+#define END_KEY_BASE			(SOC_KEYS_BASE + 0x0044)
+#define END_KEY_SIZE			U(32)
+
+/* Base Element RAM error definitions */
+#define SOC_NS_RAM_ERR_REC_BASE		UL(0x2A4C0000)
+#define NS_RAM_ECC_CE_INT		U(87)
+#define NS_RAM_ECC_UE_INT		U(88)
+
+#define SOC_PLATFORM_PERIPH_MAP_DEVICE	MAP_REGION_FLAT(			\
+						SOC_PLATFORM_PERIPH_BASE, 	\
+						SOC_PLATFORM_PERIPH_SIZE, 	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#if SPM_MM
+/*
+ * Memory map definition for the platform peripheral memory region that is
+ * accessible from S-EL0 (with secure user mode access).
+ */
+#define SOC_PLATFORM_PERIPH_MAP_DEVICE_USER				       \
+		MAP_REGION_FLAT(					       \
+			SOC_PLATFORM_PERIPH_BASE,			       \
+			SOC_PLATFORM_PERIPH_SIZE,			       \
+			MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
+#endif
+
+#define SOC_SYSTEM_PERIPH_MAP_DEVICE	MAP_REGION_FLAT(			\
+						SOC_SYSTEM_PERIPH_BASE,		\
+						SOC_SYSTEM_PERIPH_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define SOC_MEMCNTRL_MAP_DEVICE		MAP_REGION_FLAT(			\
+						SOC_MEMCNTRL_BASE,		\
+						SOC_MEMCNTRL_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(n)					\
+		MAP_REGION_FLAT(						\
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(n) + SOC_MEMCNTRL_BASE,	\
+			SOC_MEMCNTRL_SIZE,					\
+			MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * The bootsec_bridge controls access to a bunch of peripherals, e.g. the UARTs.
+ */
+#define SOC_CSS_NIC400_BOOTSEC_BRIDGE		U(5)
+#define SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1	UL(1 << 12)
+
+/*
+ * Required platform porting definitions common to all ARM CSS SoCs
+ */
+/* 2MB used for SCP DDR retraining */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE	UL(0x00200000)
+
+/* V2M motherboard system registers & offsets */
+#define V2M_SYSREGS_BASE		UL(0x0C010000)
+#define V2M_SYS_LED			U(0x8)
+
+/*
+ * V2M sysled bit definitions. The values written to this
+ * register are defined in arch.h & runtime_svc.h. Only
+ * used by the primary cpu to diagnose any cold boot issues.
+ *
+ * SYS_LED[0]   - Security state (S=0/NS=1)
+ * SYS_LED[2:1] - Exception Level (EL3-EL0)
+ * SYS_LED[7:3] - Exception Class (Sync/Async & origin)
+ *
+ */
+#define V2M_SYS_LED_SS_SHIFT		U(0)
+#define V2M_SYS_LED_EL_SHIFT		U(1)
+#define V2M_SYS_LED_EC_SHIFT		U(3)
+
+#define V2M_SYS_LED_SS_MASK		U(0x01)
+#define V2M_SYS_LED_EL_MASK		U(0x03)
+#define V2M_SYS_LED_EC_MASK		U(0x1f)
+
+/* NOR Flash */
+#define V2M_FLASH0_BASE			UL(0x08000000)
+#define V2M_FLASH0_SIZE			UL(0x04000000)
+#define V2M_FLASH_BLOCK_SIZE		UL(0x00040000)	/* 256 KB */
+
+/*
+ * The flash can be mapped either as read-only or read-write.
+ *
+ * If it is read-write then it should also be mapped as device memory because
+ * NOR flash programming involves sending a fixed, ordered sequence of commands.
+ *
+ * If it is read-only then it should also be mapped as:
+ * - Normal memory, because reading from NOR flash is transparent, it is like
+ *   reading from RAM.
+ * - Non-executable by default. If some parts of the flash need to be executable
+ *   then platform code is responsible for re-mapping the appropriate portion
+ *   of it as executable.
+ */
+#define V2M_MAP_FLASH0_RW		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define V2M_MAP_FLASH0_RO		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_RO_DATA | MT_SECURE)
+
+#define SGI_MAP_FLASH0_RO		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_DEVICE | MT_RO | MT_SECURE)
+
+/* Platform ID address */
+#define BOARD_CSS_PLAT_ID_REG_ADDR		UL(0x0EFE00E0)
+
+/* Platform ID related accessors */
+#define BOARD_CSS_PLAT_ID_REG_ID_MASK		U(0x0F)
+#define BOARD_CSS_PLAT_ID_REG_ID_SHIFT		U(0x00)
+#define BOARD_CSS_PLAT_ID_REG_VERSION_MASK	U(0xF00)
+#define BOARD_CSS_PLAT_ID_REG_VERSION_SHIFT	U(0x08)
+#define BOARD_CSS_PLAT_TYPE_RTL			U(0x00)
+#define BOARD_CSS_PLAT_TYPE_FPGA		U(0x01)
+#define BOARD_CSS_PLAT_TYPE_EMULATOR		U(0x02)
+#define BOARD_CSS_PLAT_TYPE_FVP			U(0x03)
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+
+#define BOARD_CSS_GET_PLAT_TYPE(addr)					\
+	((mmio_read_32(addr) & BOARD_CSS_PLAT_ID_REG_ID_MASK)		\
+	>> BOARD_CSS_PLAT_ID_REG_ID_SHIFT)
+
+#endif /* __ASSEMBLER__ */
+
+
+#define MAX_IO_DEVICES			U(3)
+#define MAX_IO_HANDLES			U(4)
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FLASH_IMAGE_BASE	V2M_FLASH0_BASE
+#define PLAT_ARM_FLASH_IMAGE_MAX_SIZE	(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#if ARM_GPT_SUPPORT
+/*
+ * Offset of the FIP in the GPT image. BL1 component uses this option
+ * as it does not load the partition table to get the FIP base
+ * address. At sector 34 by default (i.e. after reserved sectors 0-33)
+ * Offset = 34 * 512(sector size) = 17408 i.e. 0x4400
+ */
+#define PLAT_ARM_FIP_OFFSET_IN_GPT		0x4400
+#endif /* ARM_GPT_SUPPORT */
+
+#define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#endif /* NRD_SOC_CSS_DEF_V2_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_soc_platform_def.h b/plat/arm/css/neoverse_rd/include/nrd_soc_platform_def.h
new file mode 100644
index 0000000..0024e49
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_soc_platform_def.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_SOC_PLATFORM_DEF_H
+#define NRD_SOC_PLATFORM_DEF_H
+
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+
+#include <nrd_base_platform_def.h>
+#include <nrd_soc_css_def.h>
+
+/* Map the System registers to access from S-EL0 */
+#define CSS_SYSTEMREG_DEVICE_BASE	(0x1C010000)
+#define CSS_SYSTEMREG_DEVICE_SIZE	(0x00010000)
+#define PLAT_ARM_SECURE_MAP_SYSTEMREG	MAP_REGION_FLAT(		    \
+						CSS_SYSTEMREG_DEVICE_BASE,  \
+						CSS_SYSTEMREG_DEVICE_SIZE,  \
+						(MT_DEVICE | MT_RW |	    \
+						 MT_SECURE | MT_USER))
+
+/* Map the NOR2 Flash to access from S-EL0 */
+#define CSS_NOR2_FLASH_DEVICE_BASE	(0x10000000)
+#define CSS_NOR2_FLASH_DEVICE_SIZE	(0x04000000)
+#define PLAT_ARM_SECURE_MAP_NOR2	MAP_REGION_FLAT(                    \
+						CSS_NOR2_FLASH_DEVICE_BASE, \
+						CSS_NOR2_FLASH_DEVICE_SIZE, \
+						(MT_DEVICE | MT_RW |	    \
+						 MT_SECURE | MT_USER))
+
+#endif /* NRD_SOC_PLATFORM_DEF_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_soc_platform_def_v2.h b/plat/arm/css/neoverse_rd/include/nrd_soc_platform_def_v2.h
new file mode 100644
index 0000000..2e6f354
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_soc_platform_def_v2.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_SOC_PLATFORM_DEF_V2_H
+#define NRD_SOC_PLATFORM_DEF_V2_H
+
+#include <nrd_base_platform_def.h>
+#include <nrd_soc_css_def_v2.h>
+
+/* Map the System registers to access from S-EL0 */
+#define CSS_SYSTEMREG_DEVICE_BASE	(0x0C010000)
+#define CSS_SYSTEMREG_DEVICE_SIZE	(0x00010000)
+#define PLAT_ARM_SECURE_MAP_SYSTEMREG	MAP_REGION_FLAT(                    \
+						CSS_SYSTEMREG_DEVICE_BASE,  \
+						CSS_SYSTEMREG_DEVICE_SIZE,  \
+						(MT_DEVICE | MT_RW |	    \
+						 MT_SECURE | MT_USER))
+
+/* Map the NOR2 Flash to access from S-EL0 */
+#define CSS_NOR2_FLASH_DEVICE_BASE	(0x001054000000)
+#define CSS_NOR2_FLASH_DEVICE_SIZE	(0x000004000000)
+#define PLAT_ARM_SECURE_MAP_NOR2	MAP_REGION_FLAT(                    \
+						CSS_NOR2_FLASH_DEVICE_BASE, \
+						CSS_NOR2_FLASH_DEVICE_SIZE, \
+						(MT_DEVICE | MT_RW |	    \
+						 MT_SECURE | MT_USER))
+
+#endif /* NRD_SOC_PLATFORM_DEF_V2_H */
diff --git a/plat/arm/css/neoverse_rd/include/nrd_variant.h b/plat/arm/css/neoverse_rd/include/nrd_variant.h
new file mode 100644
index 0000000..ac7c81c
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/nrd_variant.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NRD_VARIANT_H
+#define NRD_VARIANT_H
+
+/* SSC_VERSION values for SGI575 */
+#define SGI575_SSC_VER_PART_NUM			0x0783
+
+/* SID Version values for RD-N1E1-Edge */
+#define RD_N1E1_EDGE_SID_VER_PART_NUM		0x0786
+#define RD_E1_EDGE_CONFIG_ID			0x2
+
+/* SID Version values for RD-V1 */
+#define RD_V1_SID_VER_PART_NUM			0x078a
+
+/* SID Version values for RD-N2 */
+#define RD_N2_SID_VER_PART_NUM			0x07B7
+
+/* SID Version values for RD-N2 variants */
+#define RD_N2_CFG1_SID_VER_PART_NUM		0x07B6
+#define RD_N2_CFG3_SID_VER_PART_NUM		0x07F1
+
+/* SID Version values for RD-V2 */
+#define RD_V2_SID_VER_PART_NUM			0x07F2
+#define RD_V2_CONFIG_ID				0x1
+
+/* Structure containing SGI platform variant information */
+typedef struct sgi_platform_info {
+	unsigned int platform_id;	/* Part Number of the platform */
+	unsigned int config_id;		/* Config Id of the platform */
+	unsigned int chip_id;		/* Chip Id or Node number */
+	unsigned int multi_chip_mode;	/* Multi-chip mode availability */
+} sgi_platform_info_t;
+
+extern sgi_platform_info_t sgi_plat_info;
+
+/* returns the part number of the platform*/
+unsigned int plat_arm_sgi_get_platform_id(void);
+
+/* returns the configuration id of the platform */
+unsigned int plat_arm_sgi_get_config_id(void);
+
+/* returns true if operating in multi-chip configuration */
+unsigned int plat_arm_sgi_get_multi_chip_mode(void);
+
+#endif /* NRD_VARIANT_H */
diff --git a/plat/arm/css/neoverse_rd/include/plat_macros.S b/plat/arm/css/neoverse_rd/include/plat_macros.S
new file mode 100644
index 0000000..df7cfb6
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <css_macros.S>
+
+/* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant platform registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ *
+ * There are currently no platform specific regs
+ * to print.
+ * ---------------------------------------------
+ */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/css/neoverse_rd/nrd-common.mk b/plat/arm/css/neoverse_rd/nrd-common.mk
new file mode 100644
index 0000000..18769ef
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd-common.mk
@@ -0,0 +1,81 @@
+#
+# Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CSS_USE_SCMI_SDS_DRIVER		:=	1
+
+CSS_ENT_BASE			:=	plat/arm/css/neoverse_rd
+
+ENABLE_FEAT_RAS			:=	1
+
+SDEI_SUPPORT			:=	0
+
+EL3_EXCEPTION_HANDLING		:=	0
+
+HANDLE_EA_EL3_FIRST_NS		:=	0
+
+CSS_SGI_CHIP_COUNT		:=	1
+
+CSS_SGI_PLATFORM_VARIANT	:=	0
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS		:=	0
+
+CTX_INCLUDE_FPREGS		:=	1
+
+INTERCONNECT_SOURCES	:=	${CSS_ENT_BASE}/nrd_interconnect.c
+
+PLAT_INCLUDES		+=	-I${CSS_ENT_BASE}/include
+
+# GIC-600 configuration
+GICV3_SUPPORT_GIC600	:=	1
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+ENT_GIC_SOURCES		:=	${GICV3_SOURCES}		\
+				plat/common/plat_gicv3.c	\
+				plat/arm/common/arm_gicv3.c
+
+PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/aarch64/nrd_helper.S
+
+BL1_SOURCES		+=	${INTERCONNECT_SOURCES}			\
+				drivers/arm/sbsa/sbsa.c
+
+BL2_SOURCES		+=	${CSS_ENT_BASE}/nrd_image_load.c	\
+				drivers/arm/css/sds/sds.c
+
+BL31_SOURCES		+=	${INTERCONNECT_SOURCES}			\
+				${ENT_GIC_SOURCES}			\
+				${CSS_ENT_BASE}/nrd_bl31_setup.c	\
+				${CSS_ENT_BASE}/nrd_topology.c		\
+				drivers/delay_timer/generic_delay_timer.c
+
+ifneq (${RESET_TO_BL31},0)
+  $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \
+  Please set RESET_TO_BL31 to 0.")
+endif
+
+$(eval $(call add_define,CSS_SGI_CHIP_COUNT))
+
+$(eval $(call add_define,CSS_SGI_PLATFORM_VARIANT))
+
+override CSS_LOAD_SCP_IMAGES	:=	0
+override NEED_BL2U		:=	no
+override ARM_PLAT_MT		:=	1
+override PSCI_EXTENDED_STATE_ID	:=	1
+override ARM_RECOM_STATE_ID_ENC	:=	1
+
+# System coherency is managed in hardware
+HW_ASSISTED_COHERENCY	:=	1
+
+# When building for systems with hardware-assisted coherency, there's no need to
+# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
+USE_COHERENT_MEM	:=	0
+
+include plat/arm/common/arm_common.mk
+include plat/arm/css/common/css_common.mk
+include plat/arm/soc/common/soc_css.mk
+include plat/arm/board/common/board_common.mk
diff --git a/plat/arm/css/neoverse_rd/nrd_bl31_setup.c b/plat/arm/css/neoverse_rd/nrd_bl31_setup.c
new file mode 100644
index 0000000..f9e5918
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd_bl31_setup.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <drivers/generic_delay_timer.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+
+#include <nrd_ras.h>
+#include <nrd_variant.h>
+
+sgi_platform_info_t sgi_plat_info;
+
+static scmi_channel_plat_info_t sgi575_scmi_plat_info = {
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhu_ring_doorbell,
+};
+
+static scmi_channel_plat_info_t plat_rd_scmi_info[] = {
+	{
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + SENDER_REG_SET(0),
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhuv2_ring_doorbell,
+	},
+	#if (CSS_SGI_CHIP_COUNT > 1)
+	{
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),
+		.db_reg_addr = PLAT_CSS_MHU_BASE
+			+ CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1) + SENDER_REG_SET(0),
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhuv2_ring_doorbell,
+	},
+	#endif
+	#if (CSS_SGI_CHIP_COUNT > 2)
+	{
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2),
+		.db_reg_addr = PLAT_CSS_MHU_BASE +
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(2) + SENDER_REG_SET(0),
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhuv2_ring_doorbell,
+	},
+	#endif
+	#if (CSS_SGI_CHIP_COUNT > 3)
+	{
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE +
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3),
+		.db_reg_addr = PLAT_CSS_MHU_BASE +
+			CSS_SGI_REMOTE_CHIP_MEM_OFFSET(3) + SENDER_REG_SET(0),
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhuv2_ring_doorbell,
+	},
+	#endif
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info(unsigned int channel_id)
+{
+	if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM ||
+		sgi_plat_info.platform_id == RD_V1_SID_VER_PART_NUM ||
+		sgi_plat_info.platform_id == RD_N2_SID_VER_PART_NUM ||
+		sgi_plat_info.platform_id == RD_V2_SID_VER_PART_NUM ||
+		sgi_plat_info.platform_id == RD_N2_CFG1_SID_VER_PART_NUM ||
+		sgi_plat_info.platform_id == RD_N2_CFG3_SID_VER_PART_NUM) {
+		if (channel_id >= ARRAY_SIZE(plat_rd_scmi_info)) {
+			panic();
+		}
+		return &plat_rd_scmi_info[channel_id];
+	} else if (sgi_plat_info.platform_id == SGI575_SSC_VER_PART_NUM) {
+		return &sgi575_scmi_plat_info;
+	} else {
+		panic();
+	}
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	sgi_plat_info.platform_id = plat_arm_sgi_get_platform_id();
+	sgi_plat_info.config_id = plat_arm_sgi_get_config_id();
+	sgi_plat_info.multi_chip_mode = plat_arm_sgi_get_multi_chip_mode();
+
+	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+}
+
+void sgi_bl31_common_platform_setup(void)
+{
+	generic_delay_timer_init();
+
+	arm_bl31_platform_setup();
+
+	/* Configure the warm reboot SGI for primary core */
+	css_setup_cpu_pwr_down_intr();
+
+#if CSS_SYSTEM_GRACEFUL_RESET
+	/* Register priority level handlers for reboot */
+	ehf_register_priority_handler(PLAT_REBOOT_PRI,
+			css_reboot_interrupt_handler);
+#endif
+}
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+	/*
+	 * For RD-E1-Edge, only CPU power ON/OFF, PSCI platform callbacks are
+	 * supported.
+	 */
+	if (((sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) &&
+	    (sgi_plat_info.config_id == RD_E1_EDGE_CONFIG_ID))) {
+		ops->cpu_standby = NULL;
+		ops->system_off = NULL;
+		ops->system_reset = NULL;
+		ops->get_sys_suspend_power_state = NULL;
+		ops->pwr_domain_suspend = NULL;
+		ops->pwr_domain_suspend_finish = NULL;
+	}
+
+	return css_scmi_override_pm_ops(ops);
+}
diff --git a/plat/arm/css/neoverse_rd/nrd_image_load.c b/plat/arm/css/neoverse_rd/nrd_image_load.c
new file mode 100644
index 0000000..b47f07a
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd_image_load.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/css/sds.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <nrd_base_platform_def.h>
+#include <nrd_variant.h>
+
+/*
+ * Information about the isolated CPUs obtained from SDS.
+ */
+struct isolated_cpu_mpid_list {
+	uint64_t num_entries; /* Number of entries in the list */
+	uint64_t mpid_list[PLATFORM_CORE_COUNT]; /* List of isolated CPU MPIDs */
+};
+
+/* Function to read isolated CPU MPID list from SDS. */
+void plat_arm_sgi_get_isolated_cpu_list(struct isolated_cpu_mpid_list *list)
+{
+	int ret;
+
+	ret = sds_init(SDS_SCP_AP_REGION_ID);
+	if (ret != SDS_OK) {
+		ERROR("SDS initialization failed, error: %d\n", ret);
+		panic();
+	}
+
+	ret = sds_struct_read(SDS_SCP_AP_REGION_ID,
+			SDS_ISOLATED_CPU_LIST_ID, 0, &list->num_entries,
+			sizeof(list->num_entries), SDS_ACCESS_MODE_CACHED);
+	if (ret != SDS_OK) {
+		INFO("SDS CPU num elements read failed, error: %d\n", ret);
+		list->num_entries = 0;
+		return;
+	}
+
+	if (list->num_entries > PLATFORM_CORE_COUNT) {
+		ERROR("Isolated CPU list count %ld greater than max"
+		      " number supported %d\n",
+		      list->num_entries, PLATFORM_CORE_COUNT);
+		panic();
+	} else if (list->num_entries == 0) {
+		INFO("SDS isolated CPU list is empty\n");
+		return;
+	}
+
+	ret = sds_struct_read(SDS_SCP_AP_REGION_ID,
+			SDS_ISOLATED_CPU_LIST_ID,
+			sizeof(list->num_entries),
+			&list->mpid_list,
+			sizeof(list->mpid_list[0]) * list->num_entries,
+			SDS_ACCESS_MODE_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("SDS CPU list read failed. error: %d\n", ret);
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * This function inserts Platform information via device tree nodes as,
+ * system-id {
+ *    platform-id = <0>;
+ *    config-id = <0>;
+ *    isolated-cpu-list = <0>
+ * }
+ ******************************************************************************/
+static int plat_sgi_append_config_node(void)
+{
+	bl_mem_params_node_t *mem_params;
+	void *fdt;
+	int nodeoffset, err;
+	unsigned int platid = 0, platcfg = 0;
+	struct isolated_cpu_mpid_list cpu_mpid_list = {0};
+
+	mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
+	if (mem_params == NULL) {
+		ERROR("NT_FW CONFIG base address is NULL");
+		return -1;
+	}
+
+	fdt = (void *)(mem_params->image_info.image_base);
+
+	/* Check the validity of the fdt */
+	if (fdt_check_header(fdt) != 0) {
+		ERROR("Invalid NT_FW_CONFIG DTB passed\n");
+		return -1;
+	}
+
+	nodeoffset = fdt_subnode_offset(fdt, 0, "system-id");
+	if (nodeoffset < 0) {
+		ERROR("Failed to get system-id node offset\n");
+		return -1;
+	}
+
+	platid = plat_arm_sgi_get_platform_id();
+	err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid);
+	if (err < 0) {
+		ERROR("Failed to set platform-id\n");
+		return -1;
+	}
+
+	platcfg = plat_arm_sgi_get_config_id();
+	err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg);
+	if (err < 0) {
+		ERROR("Failed to set config-id\n");
+		return -1;
+	}
+
+	platcfg = plat_arm_sgi_get_multi_chip_mode();
+	err = fdt_setprop_u32(fdt, nodeoffset, "multi-chip-mode", platcfg);
+	if (err < 0) {
+		ERROR("Failed to set multi-chip-mode\n");
+		return -1;
+	}
+
+	plat_arm_sgi_get_isolated_cpu_list(&cpu_mpid_list);
+	if (cpu_mpid_list.num_entries > 0) {
+		err = fdt_setprop(fdt, nodeoffset, "isolated-cpu-list",
+				&cpu_mpid_list,
+				(sizeof(cpu_mpid_list.num_entries) *
+				(cpu_mpid_list.num_entries + 1)));
+		if (err < 0) {
+			ERROR("Failed to set isolated-cpu-list, error: %d\n",
+			      err);
+		}
+	}
+
+	flush_dcache_range((uintptr_t)fdt, mem_params->image_info.image_size);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	int ret;
+
+	ret = plat_sgi_append_config_node();
+	if (ret != 0)
+		panic();
+
+	return arm_get_next_bl_params();
+}
diff --git a/plat/arm/css/neoverse_rd/nrd_interconnect.c b/plat/arm/css/neoverse_rd/nrd_interconnect.c
new file mode 100644
index 0000000..4f9cc85
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd_interconnect.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * For SGI575 which support FCM (with automatic interconnect enter/exit),
+ * we should not do anything in these interface functions.
+ * They are used to override the weak functions in cci drivers.
+ */
+
+/******************************************************************************
+ * Helper function to initialize ARM interconnect driver.
+ *****************************************************************************/
+void __init plat_arm_interconnect_init(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_arm_interconnect_enter_coherency(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_arm_interconnect_exit_coherency(void)
+{
+}
diff --git a/plat/arm/css/neoverse_rd/nrd_plat.c b/plat/arm/css/neoverse_rd/nrd_plat.c
new file mode 100644
index 0000000..c713ebd
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd_plat.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <drivers/arm/css/sds.h>
+#include <lib/utils_def.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+
+#include <nrd_base_platform_def.h>
+
+#if SPM_MM
+#include <services/spm_mm_partition.h>
+#endif
+
+#define SGI_MAP_FLASH0_RO	MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_DEVICE | MT_RO | MT_SECURE)
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * arm_configure_mmu_elx() will give the available subset of that.
+ *
+ * Replace or extend the below regions as required
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	SGI_MAP_FLASH0_RO,
+	CSS_SGI_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	SGI_MAP_FLASH0_RO,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	CSS_SGI_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	ARM_MAP_NS_DRAM1,
+#if CSS_SGI_CHIP_COUNT > 1
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
+#if ARM_BL31_IN_DRAM
+	ARM_MAP_BL31_SEC_DRAM,
+#endif
+#if SPM_MM
+	ARM_SP_IMAGE_MMAP,
+#endif
+#if TRUSTED_BOARD_BOOT && !RESET_TO_BL2
+	ARM_MAP_BL1_RW,
+#endif
+	{0}
+};
+#endif
+#if IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_IOFPGA,
+	CSS_SGI_MAP_DEVICE,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	SOC_CSS_MAP_DEVICE,
+#if SPM_MM
+	ARM_SPM_BUF_EL3_MMAP,
+#endif
+	{0}
+};
+
+#if SPM_MM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+	PLAT_ARM_SECURE_MAP_SYSTEMREG,
+	PLAT_ARM_SECURE_MAP_NOR2,
+	SOC_PLATFORM_SECURE_UART,
+	PLAT_ARM_SECURE_MAP_DEVICE,
+	ARM_SP_IMAGE_MMAP,
+	ARM_SP_IMAGE_NS_BUF_MMAP,
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
+	CSS_SGI_SP_CPER_BUF_MMAP,
+#endif
+	ARM_SP_IMAGE_RW_MMAP,
+	ARM_SPM_BUF_EL0_MMAP,
+	{0}
+};
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+#endif
+
+ARM_CASSERT_MMAP
+
+#if SPM_MM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static spm_mm_mp_info_t sp_mp_info[] = {
+	[0] = {0x81000000, 0},
+	[1] = {0x81000100, 0},
+	[2] = {0x81000200, 0},
+	[3] = {0x81000300, 0},
+	[4] = {0x81010000, 0},
+	[5] = {0x81010100, 0},
+	[6] = {0x81010200, 0},
+	[7] = {0x81010300, 0},
+};
+
+const spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+	.h.type              = PARAM_SP_IMAGE_BOOT_INFO,
+	.h.version           = VERSION_1,
+	.h.size              = sizeof(spm_mm_boot_info_t),
+	.h.attr              = 0,
+	.sp_mem_base         = ARM_SP_IMAGE_BASE,
+	.sp_mem_limit        = ARM_SP_IMAGE_LIMIT,
+	.sp_image_base       = ARM_SP_IMAGE_BASE,
+	.sp_stack_base       = PLAT_SP_IMAGE_STACK_BASE,
+	.sp_heap_base        = ARM_SP_IMAGE_HEAP_BASE,
+	.sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE,
+	.sp_shared_buf_base  = PLAT_SPM_BUF_BASE,
+	.sp_image_size       = ARM_SP_IMAGE_SIZE,
+	.sp_pcpu_stack_size  = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+	.sp_heap_size        = ARM_SP_IMAGE_HEAP_SIZE,
+	.sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE,
+	.sp_shared_buf_size  = PLAT_SPM_BUF_SIZE,
+	.num_sp_mem_regions  = ARM_SP_IMAGE_NUM_MEM_REGIONS,
+	.num_cpus            = PLATFORM_CORE_COUNT,
+	.mp_info             = &sp_mp_info[0],
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+	return plat_arm_secure_partition_mmap;
+}
+
+const struct spm_mm_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie)
+{
+	return &plat_arm_secure_partition_boot_info;
+}
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+
+#if TRUSTED_BOARD_BOOT
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	assert(heap_addr != NULL);
+	assert(heap_size != NULL);
+
+	return arm_get_mbedtls_heap(heap_addr, heap_size);
+}
+#endif
+
+void plat_arm_secure_wdt_start(void)
+{
+	sbsa_wdog_start(SBSA_SECURE_WDOG_BASE, SBSA_SECURE_WDOG_TIMEOUT);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE);
+}
+
+static sds_region_desc_t sgi_sds_regions[] = {
+	{ .base = PLAT_ARM_SDS_MEM_BASE },
+};
+
+sds_region_desc_t *plat_sds_get_regions(unsigned int *region_count)
+{
+	*region_count = ARRAY_SIZE(sgi_sds_regions);
+
+	return sgi_sds_regions;
+}
diff --git a/plat/arm/css/neoverse_rd/nrd_plat_v2.c b/plat/arm/css/neoverse_rd/nrd_plat_v2.c
new file mode 100644
index 0000000..d241f70
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd_plat_v2.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <lib/utils_def.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/arm/sbsa.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#if SPM_MM
+#include <services/spm_mm_partition.h>
+#endif
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	SGI_MAP_FLASH0_RO,
+	CSS_SGI_MAP_DEVICE,
+	SOC_PLATFORM_PERIPH_MAP_DEVICE,
+	SOC_SYSTEM_PERIPH_MAP_DEVICE,
+	{0}
+};
+#endif
+
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	SGI_MAP_FLASH0_RO,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	CSS_SGI_MAP_DEVICE,
+	SOC_MEMCNTRL_MAP_DEVICE,
+	SOC_PLATFORM_PERIPH_MAP_DEVICE,
+	SOC_SYSTEM_PERIPH_MAP_DEVICE,
+	ARM_MAP_NS_DRAM1,
+#if CSS_SGI_CHIP_COUNT > 1
+	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(1),
+#endif
+#if CSS_SGI_CHIP_COUNT > 2
+	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(2),
+#endif
+#if CSS_SGI_CHIP_COUNT > 3
+	SOC_MEMCNTRL_MAP_DEVICE_REMOTE_CHIP(3),
+#endif
+#if ARM_BL31_IN_DRAM
+	ARM_MAP_BL31_SEC_DRAM,
+#endif
+#if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
+	ARM_SP_IMAGE_MMAP,
+#endif
+#if TRUSTED_BOARD_BOOT && !RESET_TO_BL2
+	ARM_MAP_BL1_RW,
+#endif
+	{0}
+};
+#endif
+
+#if IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	CSS_SGI_MAP_DEVICE,
+	SOC_PLATFORM_PERIPH_MAP_DEVICE,
+	SOC_SYSTEM_PERIPH_MAP_DEVICE,
+#if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
+	ARM_SPM_BUF_EL3_MMAP,
+#endif
+	{0}
+};
+
+#if SPM_MM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+	PLAT_ARM_SECURE_MAP_SYSTEMREG,
+	PLAT_ARM_SECURE_MAP_NOR2,
+	SOC_PLATFORM_SECURE_UART,
+	SOC_PLATFORM_PERIPH_MAP_DEVICE_USER,
+	ARM_SP_IMAGE_MMAP,
+	ARM_SP_IMAGE_NS_BUF_MMAP,
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
+	CSS_SGI_SP_CPER_BUF_MMAP,
+#endif
+	ARM_SP_IMAGE_RW_MMAP,
+	ARM_SPM_BUF_EL0_MMAP,
+	{0}
+};
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+#endif
+
+ARM_CASSERT_MMAP
+
+#if SPM_MM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static spm_mm_mp_info_t sp_mp_info[] = {
+	[0] = {0x81000000, 0},
+	[1] = {0x81010000, 0},
+	[2] = {0x81020000, 0},
+	[3] = {0x81030000, 0},
+	[4] = {0x81040000, 0},
+	[5] = {0x81050000, 0},
+	[6] = {0x81060000, 0},
+	[7] = {0x81070000, 0},
+	[8] = {0x81080000, 0},
+	[9] = {0x81090000, 0},
+	[10] = {0x810a0000, 0},
+	[11] = {0x810b0000, 0},
+	[12] = {0x810c0000, 0},
+	[13] = {0x810d0000, 0},
+	[14] = {0x810e0000, 0},
+	[15] = {0x810f0000, 0},
+};
+
+const spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+	.h.type              = PARAM_SP_IMAGE_BOOT_INFO,
+	.h.version           = VERSION_1,
+	.h.size              = sizeof(spm_mm_boot_info_t),
+	.h.attr              = 0,
+	.sp_mem_base         = ARM_SP_IMAGE_BASE,
+	.sp_mem_limit        = ARM_SP_IMAGE_LIMIT,
+	.sp_image_base       = ARM_SP_IMAGE_BASE,
+	.sp_stack_base       = PLAT_SP_IMAGE_STACK_BASE,
+	.sp_heap_base        = ARM_SP_IMAGE_HEAP_BASE,
+	.sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE,
+	.sp_shared_buf_base  = PLAT_SPM_BUF_BASE,
+	.sp_image_size       = ARM_SP_IMAGE_SIZE,
+	.sp_pcpu_stack_size  = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+	.sp_heap_size        = ARM_SP_IMAGE_HEAP_SIZE,
+	.sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE,
+	.sp_shared_buf_size  = PLAT_SPM_BUF_SIZE,
+	.num_sp_mem_regions  = ARM_SP_IMAGE_NUM_MEM_REGIONS,
+	.num_cpus            = PLATFORM_CORE_COUNT,
+	.mp_info             = &sp_mp_info[0],
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+	return plat_arm_secure_partition_mmap;
+}
+
+const struct spm_mm_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie)
+{
+	return &plat_arm_secure_partition_boot_info;
+}
+#endif /* SPM_MM && defined(IMAGE_BL31) */
+
+#if TRUSTED_BOARD_BOOT
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	assert(heap_addr != NULL);
+	assert(heap_size != NULL);
+
+	return arm_get_mbedtls_heap(heap_addr, heap_size);
+}
+#endif
+
+void plat_arm_secure_wdt_start(void)
+{
+	sbsa_wdog_start(SBSA_SECURE_WDOG_BASE, SBSA_SECURE_WDOG_TIMEOUT);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE);
+}
+
+static sds_region_desc_t sgi_sds_regions[] = {
+	{ .base = PLAT_ARM_SDS_MEM_BASE },
+};
+
+sds_region_desc_t *plat_sds_get_regions(unsigned int *region_count)
+{
+	*region_count = ARRAY_SIZE(sgi_sds_regions);
+
+	return sgi_sds_regions;
+}
diff --git a/plat/arm/css/neoverse_rd/nrd_topology.c b/plat/arm/css/neoverse_rd/nrd_topology.c
new file mode 100644
index 0000000..40be049
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/nrd_topology.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * Common topology related methods for SGI and RD based platforms
+ */
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
+{
+	return CSS_SGI_MAX_CPUS_PER_CLUSTER;
+}
+
+#if ARM_PLAT_MT
+/******************************************************************************
+ * Return the number of PE's supported by the CPU.
+ *****************************************************************************/
+unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr)
+{
+	return CSS_SGI_MAX_PE_PER_CPU;
+}
+#endif
diff --git a/plat/arm/css/neoverse_rd/ras/nrd_ras_common.c b/plat/arm/css/neoverse_rd/ras/nrd_ras_common.c
new file mode 100644
index 0000000..d920560
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/ras/nrd_ras_common.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <nrd_ras.h>
+
+static struct plat_sgi_ras_config *sgi_ras_config;
+
+/*
+ * Find event map for a given interrupt number. On success, returns pointer to
+ * the event map. On error, returns NULL.
+ */
+struct sgi_ras_ev_map *sgi_find_ras_event_map_by_intr(uint32_t intr_num)
+{
+	struct sgi_ras_ev_map *map;
+	int size;
+	int i;
+
+	if (sgi_ras_config == NULL) {
+		ERROR("RAS config is NULL\n");
+		return NULL;
+	}
+
+	map = sgi_ras_config->ev_map;
+	size = sgi_ras_config->ev_map_size;
+
+	for (i = 0; i < size; i++) {
+		if (map->intr == intr_num)
+			return map;
+
+		map++;
+	}
+
+	return NULL;
+}
+
+/*
+ * Programs GIC registers and configures interrupt ID's as Group0 EL3
+ * interrupts. Current support is to register PPI and SPI interrupts.
+ */
+static void sgi_ras_intr_configure(int intr, int intr_type)
+{
+	plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3);
+	plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI);
+	plat_ic_clear_interrupt_pending(intr);
+
+	/* Routing mode option available only for SPI interrupts */
+	if (intr_type == SGI_RAS_INTR_TYPE_SPI) {
+		plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY,
+					(u_register_t)read_mpidr_el1());
+	}
+	plat_ic_enable_interrupt(intr);
+}
+
+/*
+ * Initialization function for the framework.
+ *
+ * Registers RAS config provided by the platform and then configures and
+ * enables interrupt for each registered error. On success, return 0.
+ */
+int sgi_ras_platform_setup(struct plat_sgi_ras_config *config)
+{
+	struct sgi_ras_ev_map *map;
+	int size;
+	int i;
+
+	/* Check if parameter is valid. */
+	if (config == NULL) {
+		ERROR("SGI: Failed to register RAS config\n");
+		return -1;
+	}
+
+	/*
+	 * Maintain a reference to the platform RAS config data for later
+	 * use.
+	 */
+	sgi_ras_config = config;
+
+	map = sgi_ras_config->ev_map;
+	size = sgi_ras_config->ev_map_size;
+
+	for (i = 0; i < size; i++) {
+		sgi_ras_intr_configure(map->intr, map->intr_type);
+		map++;
+	}
+
+	INFO("SGI: Platform RAS setup successful\n");
+
+	return 0;
+}
diff --git a/plat/arm/css/neoverse_rd/ras/nrd_ras_cpu.c b/plat/arm/css/neoverse_rd/ras/nrd_ras_cpu.c
new file mode 100644
index 0000000..71d1775
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/ras/nrd_ras_cpu.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/extensions/ras.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+#include <services/spm_mm_svc.h>
+
+#include <nrd_ras.h>
+
+#define CPU_CONTEXT_REG_GPR_ARR_SIZE 32
+#define CPU_CONTEXT_REG_EL1_ARR_SIZE 17
+#define CPU_CONTEXT_REG_EL2_ARR_SIZE 16
+#define CPU_CONTEXT_REG_EL3_ARR_SIZE 10
+
+/*
+ * MM Communicate message header GUID to indicate the payload is intended for
+ * CPU MM driver.
+ */
+struct efi_guid cpu_ecc_event_guid = {
+	0x2c1b3bfc, 0x42cd, 0x4a66,
+	{0xac, 0xd1, 0xa4, 0xd1, 0x63, 0xe9, 0x90, 0xf6}
+	};
+
+/*
+ * CPU error information data structure communicated as part of MM
+ * Communication data payload.
+ */
+typedef struct {
+	uint64_t ErrStatus;
+	uint64_t ErrMisc0;
+	uint64_t ErrAddr;
+	uint64_t SecurityState;
+	uint64_t ErrCtxGpr[CPU_CONTEXT_REG_GPR_ARR_SIZE];
+	uint64_t ErrCtxEl1Reg[CPU_CONTEXT_REG_EL1_ARR_SIZE];
+	uint64_t ErrCtxEl2Reg[CPU_CONTEXT_REG_EL2_ARR_SIZE];
+	uint64_t ErrCtxEl3Reg[CPU_CONTEXT_REG_EL3_ARR_SIZE];
+} cpu_err_info;
+
+/*
+ * Reads the CPU context and error information from the relevant registers and
+ * populates the CPU error information data structure.
+ */
+static void populate_cpu_err_data(cpu_err_info *cpu_info,
+					uint64_t security_state)
+{
+	void *ctx;
+
+	ctx = cm_get_context(security_state);
+
+	cpu_info->ErrStatus = read_erxstatus_el1();
+	cpu_info->ErrMisc0 = read_erxmisc0_el1();
+	cpu_info->ErrAddr = read_erxaddr_el1();
+	cpu_info->SecurityState = security_state;
+
+	/* populate CPU EL1 context information. */
+	cpu_info->ErrCtxEl1Reg[0]  = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_ELR_EL1);
+	cpu_info->ErrCtxEl1Reg[1]  = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_ESR_EL1);
+	cpu_info->ErrCtxEl1Reg[2]  = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_FAR_EL1);
+	cpu_info->ErrCtxEl1Reg[3]  = read_isr_el1();
+	cpu_info->ErrCtxEl1Reg[4]  = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_MAIR_EL1);
+	cpu_info->ErrCtxEl1Reg[5]  = read_midr_el1();
+	cpu_info->ErrCtxEl1Reg[6]  = read_mpidr_el1();
+	cpu_info->ErrCtxEl1Reg[7]  = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_SCTLR_EL1);
+	cpu_info->ErrCtxEl1Reg[8]  = read_ctx_reg(get_gpregs_ctx(ctx),
+						  CTX_GPREG_SP_EL0);
+	cpu_info->ErrCtxEl1Reg[9]  = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_SP_EL1);
+	cpu_info->ErrCtxEl1Reg[10] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_SPSR_EL1);
+	cpu_info->ErrCtxEl1Reg[11] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_TCR_EL1);
+	cpu_info->ErrCtxEl1Reg[12] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_TPIDR_EL0);
+	cpu_info->ErrCtxEl1Reg[13] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_TPIDR_EL1);
+	cpu_info->ErrCtxEl1Reg[14] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_TPIDRRO_EL0);
+	cpu_info->ErrCtxEl1Reg[15] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_TTBR0_EL1);
+	cpu_info->ErrCtxEl1Reg[16] = read_ctx_reg(get_el1_sysregs_ctx(ctx),
+						  CTX_TTBR1_EL1);
+
+#if CTX_INCLUDE_EL2_REGS
+	cpu_info->ErrCtxEl2Reg[0]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_ELR_EL2);
+	cpu_info->ErrCtxEl2Reg[1]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_ESR_EL2);
+	cpu_info->ErrCtxEl2Reg[2]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_FAR_EL2);
+	cpu_info->ErrCtxEl2Reg[3]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_HACR_EL2);
+	cpu_info->ErrCtxEl2Reg[4]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_HCR_EL2);
+	cpu_info->ErrCtxEl2Reg[5]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_HPFAR_EL2);
+	cpu_info->ErrCtxEl2Reg[6]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_MAIR_EL2);
+	cpu_info->ErrCtxEl2Reg[7]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_SCTLR_EL2);
+	cpu_info->ErrCtxEl2Reg[8]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_SP_EL2);
+	cpu_info->ErrCtxEl2Reg[9]   = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_SPSR_EL2);
+	cpu_info->ErrCtxEl2Reg[10]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_TCR_EL2);
+	cpu_info->ErrCtxEl2Reg[11]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_TPIDR_EL2);
+	cpu_info->ErrCtxEl2Reg[12]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_TTBR0_EL2);
+	cpu_info->ErrCtxEl2Reg[13]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_VTCR_EL2);
+	cpu_info->ErrCtxEl2Reg[14]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_VTTBR_EL2);
+	cpu_info->ErrCtxEl2Reg[15]  = read_ctx_reg(get_el2_sysregs_ctx(ctx),
+						   CTX_ESR_EL2);
+#endif
+
+	cpu_info->ErrCtxEl3Reg[0]   = read_ctx_reg(get_el3state_ctx(ctx),
+						   CTX_ELR_EL3);
+	cpu_info->ErrCtxEl3Reg[1]   = read_ctx_reg(get_el3state_ctx(ctx),
+						   CTX_ESR_EL3);
+	cpu_info->ErrCtxEl3Reg[2]   = read_far_el3();
+	cpu_info->ErrCtxEl3Reg[4]   = read_mair_el3();
+	cpu_info->ErrCtxEl3Reg[5]   = read_sctlr_el3();
+	cpu_info->ErrCtxEl3Reg[6]   = 0; /* sp_el3 */
+	cpu_info->ErrCtxEl3Reg[7]   = read_tcr_el3();
+	cpu_info->ErrCtxEl3Reg[8]   = read_tpidr_el3();
+	cpu_info->ErrCtxEl3Reg[9]   = read_ttbr0_el3();
+}
+
+/* CPU RAS interrupt handler */
+int sgi_ras_cpu_intr_handler(const struct err_record_info *err_rec,
+				int probe_data,
+				const struct err_handler_data *const data)
+{
+	struct sgi_ras_ev_map *ras_map;
+	mm_communicate_header_t *header;
+	cpu_err_info cpu_info = {0};
+	uint64_t clear_status;
+	uint32_t intr;
+	int ret;
+
+	cm_el1_sysregs_context_save(NON_SECURE);
+	intr = data->interrupt;
+
+	INFO("[CPU RAS] CPU intr received = %d on cpu_id = %d\n",
+		intr, plat_my_core_pos());
+
+	INFO("[CPU RAS] ERXMISC0_EL1 = 0x%lx\n", read_erxmisc0_el1());
+	INFO("[CPU RAS] ERXSTATUS_EL1 = 0x%lx\n", read_erxstatus_el1());
+	INFO("[CPU RAS] ERXADDR_EL1 = 0x%lx\n", read_erxaddr_el1());
+
+	/* Populate CPU Error Source Information. */
+	populate_cpu_err_data(&cpu_info, get_interrupt_src_ss(data->flags));
+
+	/* Clear the interrupt. */
+	clear_status = read_erxstatus_el1();
+	write_erxstatus_el1(clear_status);
+	plat_ic_end_of_interrupt(intr);
+
+	header = (void *) PLAT_SPM_BUF_BASE;
+	memset(header, 0, sizeof(*header));
+	memcpy(&header->data, &cpu_info, sizeof(cpu_info));
+	header->message_len = sizeof(cpu_info);
+	memcpy(&header->header_guid, (void *) &cpu_ecc_event_guid,
+		sizeof(struct efi_guid));
+
+	spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
+		       plat_my_core_pos());
+
+	/*
+	 * Find if this is a RAS interrupt. There must be an event against
+	 * this interrupt
+	 */
+	ras_map = sgi_find_ras_event_map_by_intr(intr);
+	if (ras_map == NULL) {
+		ERROR("SGI: RAS error info for interrupt id: %d not found\n",
+			intr);
+		return -1;
+	}
+
+	/* Dispatch the event to the SDEI client */
+	ret = sdei_dispatch_event(ras_map->sdei_ev_num);
+	if (ret != 0) {
+		/*
+		 * sdei_dispatch_event() may return failing result in some
+		 * cases, for example kernel may not have registered a handler
+		 * or RAS event may happen early during boot. We restore the NS
+		 * context when sdei_dispatch_event() returns failing result.
+		 */
+		ERROR("SDEI dispatch failed: %d", ret);
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+	}
+
+	return ret;
+}
diff --git a/plat/arm/css/neoverse_rd/ras/nrd_ras_sram.c b/plat/arm/css/neoverse_rd/ras/nrd_ras_sram.c
new file mode 100644
index 0000000..8f4fb4c
--- /dev/null
+++ b/plat/arm/css/neoverse_rd/ras/nrd_ras_sram.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+#include <services/spm_mm_svc.h>
+
+#include <platform_def.h>
+#include <nrd_ras.h>
+
+/* Base Element RAM Error Record offsets. */
+#define ERRSTATUS	U(0)
+#define ERRCODE		U(8)
+#define ERRADDR		U(12)
+
+/*
+ * Base Element RAM error information data structure communicated as part of MM
+ * Communication data payload.
+ */
+typedef struct sgi_sram_err_info {
+	uint32_t err_status;
+	uint32_t err_code;
+	uint32_t err_addr;
+} sgi_sram_err_info_t;
+
+/*
+ * MM Communicate message header GUID to indicate the payload is intended for
+ * base element RAM MM driver.
+ */
+struct efi_guid sram_ecc_event_guid = {
+	0x7312db4f, 0xd0c4, 0x4fb5,
+	{ 0x81, 0x2c, 0xb7, 0x4b, 0xc6, 0xc4, 0xa9, 0x38 }
+};
+
+/* Base element RAM RAS error interrupt handler */
+int sgi_ras_sram_intr_handler(const struct err_record_info *err_rec,
+				int probe_data,
+				const struct err_handler_data *const data)
+{
+	struct sgi_ras_ev_map *ras_map;
+	mm_communicate_header_t *header;
+	sgi_sram_err_info_t sram_info;
+	uintptr_t base_addr;
+	uint32_t clear_status, intr;
+	int ret;
+
+	cm_el1_sysregs_context_save(NON_SECURE);
+	intr = data->interrupt;
+
+	INFO("SGI: Base element RAM interrupt [%d] handler\n", intr);
+
+	/* Determine error record base address to read. */
+	base_addr = 0;
+	if (intr == NS_RAM_ECC_CE_INT || intr == NS_RAM_ECC_UE_INT) {
+		base_addr = SOC_NS_RAM_ERR_REC_BASE;
+	}
+	sram_info.err_status = mmio_read_32(base_addr + ERRSTATUS);
+	sram_info.err_code = mmio_read_32(base_addr + ERRCODE);
+	sram_info.err_addr = mmio_read_32(base_addr + ERRADDR);
+
+	/* Clear the interrupt. */
+	clear_status = mmio_read_32(base_addr + ERRSTATUS);
+	mmio_write_32((base_addr + ERRSTATUS), clear_status);
+
+	/*
+	 * Prepare the MM Communication buffer to pass the base element RAM
+	 * error information to Secure Partition.
+	 */
+	header = (void *)PLAT_SPM_BUF_BASE;
+	memset(header, 0, sizeof(*header));
+	memcpy(&header->data, &sram_info, sizeof(sram_info));
+	header->message_len = sizeof(sram_info);
+	memcpy(&header->header_guid, (void *)&sram_ecc_event_guid,
+		sizeof(struct efi_guid));
+
+	spm_mm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
+			plat_my_core_pos());
+
+	plat_ic_end_of_interrupt(intr);
+
+	/*
+	 * Find if this is a RAS interrupt. There must be an event against
+	 * this interrupt
+	 */
+	ras_map = sgi_find_ras_event_map_by_intr(intr);
+	if (ras_map == NULL) {
+		ERROR("SGI: RAS error info for interrupt id: %d not found\n",
+			intr);
+		return -1;
+	}
+
+	/* Dispatch the event to the SDEI client */
+	ret = sdei_dispatch_event(ras_map->sdei_ev_num);
+	if (ret != 0) {
+		/*
+		 * sdei_dispatch_event() may return failing result in some
+		 * cases, for example kernel may not have registered a handler
+		 * or RAS event may happen early during boot. We restore the NS
+		 * context when sdei_dispatch_event() returns failing result.
+		 */
+		ERROR("SDEI dispatch failed: %d", ret);
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+	}
+
+	return ret;
+}