Merge "TF-A Documentation: Update Security Advisory TFV-5 (CVE-2017-15031)" into integration
diff --git a/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml b/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
index 2752b33..b7289a2 100644
--- a/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
+++ b/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
@@ -1,7 +1,7 @@
 @startuml
 
-participant arm_io_storage order 1
-participant io_storage order 2
+participant arm_io_storage
+participant io_storage
 
  -> arm_io_storage : plat_get_image_source(image_id, &dev_handle, &image_spec)
 
diff --git a/docs/resources/diagrams/plantuml/io_dev_registration.puml b/docs/resources/diagrams/plantuml/io_dev_registration.puml
index 114c3b7..c6f330e 100644
--- a/docs/resources/diagrams/plantuml/io_dev_registration.puml
+++ b/docs/resources/diagrams/plantuml/io_dev_registration.puml
@@ -1,9 +1,9 @@
 @startuml
 
-participant arm_io_storage order 1
-participant io_storage order 2
-participant io_fip order 3
-participant io_memmap order 4
+participant arm_io_storage
+participant io_storage
+participant io_fip
+participant io_memmap
 
  -> arm_io_storage : arm_io_setup()
 
diff --git a/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml b/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
index eb3e2b4..b21a0ae 100644
--- a/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
+++ b/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
@@ -1,8 +1,8 @@
 @startuml
 
-participant bl_common order 1
-participant arm_io_storage order 2
-participant io_storage order 3
+participant bl_common
+participant arm_io_storage
+participant io_storage
 
 == Platform Setup ==
 
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
new file mode 100644
index 0000000..c62c3f5
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * GIC-600 driver extension for multichip setup
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic600_multichip.h>
+
+#include "gic600_multichip_private.h"
+#include "../common/gic_common_private.h"
+
+#warning "GIC-600 Multichip driver is currently experimental and the API may change in future."
+
+/*******************************************************************************
+ * GIC-600 multichip operation related helper functions
+ ******************************************************************************/
+static void gicd_dchipr_wait_for_power_update_progress(uintptr_t base)
+{
+	unsigned int retry = GICD_PUP_UPDATE_RETRIES;
+
+	while ((read_gicd_dchipr(base) & GICD_DCHIPR_PUP_BIT) != 0U) {
+		if (retry-- == 0) {
+			ERROR("GIC-600 connection to Routing Table Owner timed "
+					 "out\n");
+			panic();
+		}
+	}
+}
+
+/*******************************************************************************
+ * Sets up the routing table owner.
+ ******************************************************************************/
+static void set_gicd_dchipr_rt_owner(uintptr_t base, unsigned int rt_owner)
+{
+	/*
+	 * Ensure that Group enables in GICD_CTLR are disabled and no pending
+	 * register writes to GICD_CTLR.
+	 */
+	if ((gicd_read_ctlr(base) &
+			(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+			 CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+		ERROR("GICD_CTLR group interrupts are either enabled or have "
+				"pending writes. Cannot set RT owner.\n");
+		panic();
+	}
+
+	/* Poll till PUP is zero before intiating write */
+	gicd_dchipr_wait_for_power_update_progress(base);
+
+	write_gicd_dchipr(base, read_gicd_dchipr(base) |
+			(rt_owner << GICD_DCHIPR_RT_OWNER_SHIFT));
+
+	/* Poll till PUP is zero to ensure write is complete */
+	gicd_dchipr_wait_for_power_update_progress(base);
+}
+
+/*******************************************************************************
+ * Configures the Chip Register to make connections to GICDs on
+ * a multichip platform.
+ ******************************************************************************/
+static void set_gicd_chipr_n(uintptr_t base,
+				unsigned int chip_id,
+				uint64_t chip_addr,
+				unsigned int spi_id_min,
+				unsigned int spi_id_max)
+{
+	unsigned int spi_block_min, spi_blocks;
+	uint64_t chipr_n_val;
+
+	/*
+	 * Ensure that group enables in GICD_CTLR are disabled and no pending
+	 * register writes to GICD_CTLR.
+	 */
+	if ((gicd_read_ctlr(base) &
+			(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+			 CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+		ERROR("GICD_CTLR group interrupts are either enabled or have "
+				"pending writes. Cannot set CHIPR register.\n");
+		panic();
+	}
+
+	/*
+	 * spi_id_min and spi_id_max of value 0 is used to intidicate that the
+	 * chip doesn't own any SPI block. Re-assign min and max values as SPI
+	 * id starts from 32.
+	 */
+	if (spi_id_min == 0 && spi_id_max == 0) {
+		spi_id_min = GIC600_SPI_ID_MIN;
+		spi_id_max = GIC600_SPI_ID_MIN;
+	}
+
+	spi_block_min = SPI_BLOCK_MIN_VALUE(spi_id_min);
+	spi_blocks    = SPI_BLOCKS_VALUE(spi_id_min, spi_id_max);
+
+	chipr_n_val = (GICD_CHIPR_VALUE(chip_addr, spi_block_min, spi_blocks)) |
+		GICD_CHIPRx_SOCKET_STATE;
+
+	/*
+	 * Wait for DCHIPR.PUP to be zero before commencing writes to
+	 * GICD_CHIPRx.
+	 */
+	gicd_dchipr_wait_for_power_update_progress(base);
+
+	/*
+	 * Assign chip addr, spi min block, number of spi blocks and bring chip
+	 * online by setting SocketState.
+	 */
+	write_gicd_chipr_n(base, chip_id, chipr_n_val);
+
+	/*
+	 * Poll until DCHIP.PUP is zero to verify connection to rt_owner chip
+	 * is complete.
+	 */
+	gicd_dchipr_wait_for_power_update_progress(base);
+
+	/*
+	 * Ensure that write to GICD_CHIPRx is successful and the chip_n came
+	 * online.
+	 */
+	if (read_gicd_chipr_n(base, chip_id) != chipr_n_val) {
+		ERROR("GICD_CHIPR%u write failed\n", chip_id);
+		panic();
+	}
+
+	/* Ensure that chip is in consistent state */
+	if (((read_gicd_chipsr(base) & GICD_CHIPSR_RTS_MASK) >>
+				GICD_CHIPSR_RTS_SHIFT) !=
+			GICD_CHIPSR_RTS_STATE_CONSISTENT) {
+		ERROR("Chip %u routing table is not in consistent state\n",
+				chip_id);
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * Validates the GIC-600 Multichip data structure passed by the platform.
+ ******************************************************************************/
+static void gic600_multichip_validate_data(
+		struct gic600_multichip_data *multichip_data)
+{
+	unsigned int i, spi_id_min, spi_id_max, blocks_of_32;
+	unsigned int multichip_spi_blocks = 0;
+
+	assert(multichip_data != NULL);
+
+	if (multichip_data->chip_count > GIC600_MAX_MULTICHIP) {
+		ERROR("GIC-600 Multichip count should not exceed %d\n",
+				GIC600_MAX_MULTICHIP);
+		panic();
+	}
+
+	for (i = 0; i < multichip_data->chip_count; i++) {
+		spi_id_min = multichip_data->spi_ids[i][SPI_MIN_INDEX];
+		spi_id_max = multichip_data->spi_ids[i][SPI_MAX_INDEX];
+
+		if ((spi_id_min != 0) || (spi_id_max != 0)) {
+
+			/* SPI IDs range check */
+			if (!(spi_id_min >= GIC600_SPI_ID_MIN) ||
+			    !(spi_id_max < GIC600_SPI_ID_MAX) ||
+			    !(spi_id_min <= spi_id_max) ||
+			    !((spi_id_max - spi_id_min + 1) % 32 == 0)) {
+				ERROR("Invalid SPI IDs {%u, %u} passed for "
+						"Chip %u\n", spi_id_min,
+						spi_id_max, i);
+				panic();
+			}
+
+			/* SPI IDs overlap check */
+			blocks_of_32 = BLOCKS_OF_32(spi_id_min, spi_id_max);
+			if ((multichip_spi_blocks & blocks_of_32) != 0) {
+				ERROR("SPI IDs of Chip %u overlapping\n", i);
+				panic();
+			}
+			multichip_spi_blocks |= blocks_of_32;
+		}
+	}
+}
+
+/*******************************************************************************
+ * Intialize GIC-600 Multichip operation.
+ ******************************************************************************/
+void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
+{
+	unsigned int i;
+
+	gic600_multichip_validate_data(multichip_data);
+
+	INFO("GIC-600 Multichip driver is experimental\n");
+
+	/*
+	 * Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
+	 * that GIC-600 Multichip configuration is done first.
+	 */
+	if ((gicd_read_ctlr(multichip_data->rt_owner_base) &
+			(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+			 CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+		ERROR("GICD_CTLR group interrupts are either enabled or have "
+				"pending writes.\n");
+		panic();
+	}
+
+	/* Ensure that the routing table owner is in disconnected state */
+	if (((read_gicd_chipsr(multichip_data->rt_owner_base) &
+		GICD_CHIPSR_RTS_MASK) >> GICD_CHIPSR_RTS_SHIFT) !=
+			GICD_CHIPSR_RTS_STATE_DISCONNECTED) {
+		ERROR("GIC-600 routing table owner is not in disconnected "
+				"state to begin multichip configuration\n");
+		panic();
+	}
+
+	/* Initialize the GICD which is marked as routing table owner first */
+	set_gicd_dchipr_rt_owner(multichip_data->rt_owner_base,
+			multichip_data->rt_owner);
+
+	set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
+			multichip_data->chip_addrs[multichip_data->rt_owner],
+			multichip_data->
+			spi_ids[multichip_data->rt_owner][SPI_MIN_INDEX],
+			multichip_data->
+			spi_ids[multichip_data->rt_owner][SPI_MAX_INDEX]);
+
+	for (i = 0; i < multichip_data->chip_count; i++) {
+		if (i == multichip_data->rt_owner)
+			continue;
+
+		set_gicd_chipr_n(multichip_data->rt_owner_base, i,
+				multichip_data->chip_addrs[i],
+				multichip_data->spi_ids[i][SPI_MIN_INDEX],
+				multichip_data->spi_ids[i][SPI_MAX_INDEX]);
+	}
+}
diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h
new file mode 100644
index 0000000..b0217b6
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600_multichip_private.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC600_MULTICHIP_PRIVATE_H
+#define GIC600_MULTICHIP_PRIVATE_H
+
+#include <drivers/arm/gic600_multichip.h>
+
+#include "gicv3_private.h"
+
+/* GIC600 GICD multichip related offsets */
+#define GICD_CHIPSR			U(0xC000)
+#define GICD_DCHIPR			U(0xC004)
+#define GICD_CHIPR			U(0xC008)
+
+/* GIC600 GICD multichip related masks */
+#define GICD_CHIPRx_PUP_BIT		BIT_64(1)
+#define GICD_CHIPRx_SOCKET_STATE	BIT_64(0)
+#define GICD_DCHIPR_PUP_BIT		BIT_32(0)
+#define GICD_CHIPSR_RTS_MASK		(BIT_32(4) | BIT_32(5))
+
+/* GIC600 GICD multichip related shifts */
+#define GICD_CHIPRx_ADDR_SHIFT		16
+#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT	10
+#define GICD_CHIPRx_SPI_BLOCKS_SHIFT	5
+#define GICD_CHIPSR_RTS_SHIFT		4
+#define GICD_DCHIPR_RT_OWNER_SHIFT	4
+
+#define GICD_CHIPSR_RTS_STATE_DISCONNECTED	U(0)
+#define GICD_CHIPSR_RTS_STATE_UPDATING		U(1)
+#define GICD_CHIPSR_RTS_STATE_CONSISTENT	U(2)
+
+/* SPI interrupt id minimum and maximum range */
+#define GIC600_SPI_ID_MIN		32
+#define GIC600_SPI_ID_MAX		960
+
+/* Number of retries for PUP update */
+#define GICD_PUP_UPDATE_RETRIES		10000
+
+#define SPI_MIN_INDEX			0
+#define SPI_MAX_INDEX			1
+
+#define SPI_BLOCK_MIN_VALUE(spi_id_min) \
+			(((spi_id_min) - GIC600_SPI_ID_MIN) / \
+			GIC600_SPI_ID_MIN)
+#define SPI_BLOCKS_VALUE(spi_id_min, spi_id_max) \
+			(((spi_id_max) - (spi_id_min) + 1) / \
+			GIC600_SPI_ID_MIN)
+#define GICD_CHIPR_VALUE(chip_addr, spi_block_min, spi_blocks) \
+			(((chip_addr) << GICD_CHIPRx_ADDR_SHIFT) | \
+			((spi_block_min) << GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT) | \
+			((spi_blocks) << GICD_CHIPRx_SPI_BLOCKS_SHIFT))
+
+/*
+ * Multichip data assertion macros
+ */
+/* Set bits from 0 to ((spi_id_max + 1) / 32) */
+#define SPI_BLOCKS_TILL_MAX(spi_id_max)	((1 << (((spi_id_max) + 1) >> 5)) - 1)
+/* Set bits from 0 to (spi_id_min / 32) */
+#define SPI_BLOCKS_TILL_MIN(spi_id_min)	((1 << ((spi_id_min) >> 5)) - 1)
+/* Set bits from (spi_id_min / 32) to ((spi_id_max + 1) / 32) */
+#define BLOCKS_OF_32(spi_id_min, spi_id_max) \
+					SPI_BLOCKS_TILL_MAX(spi_id_max) ^ \
+					SPI_BLOCKS_TILL_MIN(spi_id_min)
+
+/*******************************************************************************
+ * GIC-600 multichip operation related helper functions
+ ******************************************************************************/
+static inline uint32_t read_gicd_dchipr(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_DCHIPR);
+}
+
+static inline uint64_t read_gicd_chipr_n(uintptr_t base, uint8_t n)
+{
+	return mmio_read_64(base + (GICD_CHIPR + (8U * n)));
+}
+
+static inline uint32_t read_gicd_chipsr(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_CHIPSR);
+}
+
+static inline void write_gicd_dchipr(uintptr_t base, uint32_t val)
+{
+	mmio_write_32(base + GICD_DCHIPR, val);
+}
+
+static inline void write_gicd_chipr_n(uintptr_t base, uint8_t n, uint64_t val)
+{
+	mmio_write_64(base + (GICD_CHIPR + (8U * n)), val);
+}
+
+#endif /* GIC600_MULTICHIP_PRIVATE_H */
diff --git a/drivers/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
index 5493b85..a082a81 100644
--- a/drivers/arm/smmu/smmu_v3.c
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -7,23 +7,27 @@
 #include <common/debug.h>
 #include <cdefs.h>
 #include <drivers/arm/smmu_v3.h>
+#include <drivers/delay_timer.h>
 #include <lib/mmio.h>
 
 /* SMMU poll number of retries */
-#define SMMU_POLL_RETRY		1000000
+#define SMMU_POLL_TIMEOUT_US	U(1000)
 
 static int __init smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
 				uint32_t value)
 {
-	uint32_t reg_val, retries = SMMU_POLL_RETRY;
+	uint32_t reg_val;
+	uint64_t timeout;
 
+	/* Set 1ms timeout value */
+	timeout = timeout_init_us(SMMU_POLL_TIMEOUT_US);
 	do {
 		reg_val = mmio_read_32(smmu_reg);
 		if ((reg_val & mask) == value)
 			return 0;
-	} while (--retries != 0U);
+	} while (!timeout_elapsed(timeout));
 
-	ERROR("Failed to poll SMMUv3 register @%p\n", (void *)smmu_reg);
+	ERROR("Timeout polling SMMUv3 register @%p\n", (void *)smmu_reg);
 	ERROR("Read value 0x%x, expected 0x%x\n", reg_val,
 		value == 0U ? reg_val & ~mask : reg_val | mask);
 	return -1;
diff --git a/include/drivers/arm/gic600_multichip.h b/include/drivers/arm/gic600_multichip.h
new file mode 100644
index 0000000..bda406b
--- /dev/null
+++ b/include/drivers/arm/gic600_multichip.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC600_MULTICHIP_H
+#define GIC600_MULTICHIP_H
+
+#include <stdint.h>
+
+/*
+ * GIC-600 microarchitecture supports coherent multichip environments containing
+ * up to 16 chips.
+ */
+#define GIC600_MAX_MULTICHIP	16
+
+/* SPI IDs array consist of min and max ids */
+#define GIC600_SPI_IDS_SIZE	2
+
+/*******************************************************************************
+ * GIC-600 multichip data structure describes platform specific attributes
+ * related to GIC-600 multichip. Platform port is expected to define these
+ * attributes to initialize the multichip related registers and create
+ * successful connections between the GIC-600s in a multichip system.
+ *
+ * The 'rt_owner_base' field contains the base address of the GIC Distributor
+ * which owns the routing table.
+ *
+ * The 'rt_owner' field contains the chip number which owns the routing table.
+ * Chip number or chip_id starts from 0.
+ *
+ * The 'chip_count' field contains the total number of chips in a multichip
+ * system. This should match the number of entries in 'chip_addrs' and 'spi_ids'
+ * fields.
+ *
+ * The 'chip_addrs' field contains array of chip addresses. These addresses are
+ * implementation specific values.
+ *
+ * The 'spi_ids' field contains array of minimum and maximum SPI interrupt ids
+ * that each chip owns. Note that SPI interrupt ids can range from 32 to 960 and
+ * it should be group of 32 (i.e., SPI minimum and (SPI maximum + 1) should be
+ * a multiple of 32). If a chip doesn't own any SPI interrupts a value of {0, 0}
+ * should be passed.
+ ******************************************************************************/
+struct gic600_multichip_data {
+	uintptr_t rt_owner_base;
+	unsigned int rt_owner;
+	unsigned int chip_count;
+	uint64_t chip_addrs[GIC600_MAX_MULTICHIP];
+	unsigned int spi_ids[GIC600_MAX_MULTICHIP][GIC600_SPI_IDS_SIZE];
+};
+
+void gic600_multichip_init(struct gic600_multichip_data *multichip_data);
+#endif /* GIC600_MULTICHIP_H */
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 07a46c5..c00a041 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -254,6 +254,11 @@
 int plat_arm_bl1_fwu_needed(void);
 __dead2 void plat_arm_error_handler(int err);
 
+/*
+ * Optional function in ARM standard platforms
+ */
+void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames);
+
 #if ARM_PLAT_MT
 unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr);
 #endif
diff --git a/lib/stack_protector/stack_protector.mk b/lib/stack_protector/stack_protector.mk
index 94e804b..b5aba15 100644
--- a/lib/stack_protector/stack_protector.mk
+++ b/lib/stack_protector/stack_protector.mk
@@ -11,7 +11,9 @@
   ENABLE_STACK_PROTECTOR := none
 endif
 
-ifneq (${ENABLE_STACK_PROTECTOR},none)
+ifeq (${ENABLE_STACK_PROTECTOR},none)
+  TF_CFLAGS            +=      -fno-stack-protector
+else
   STACK_PROTECTOR_ENABLED := 1
   BL_COMMON_SOURCES	+=	lib/stack_protector/stack_protector.c	\
 				lib/stack_protector/${ARCH}/asm_stack_protector.S
diff --git a/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S b/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
index c03185a..3da55b6 100644
--- a/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
+++ b/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
@@ -17,19 +17,20 @@
 	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
 	 *
 	 * Helper function to calculate the core position.
-	 * (ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER * N1SDP_MAX_PE_PER_CPU) +
-	 * (CPUId * N1SDP_MAX_PE_PER_CPU) +
-	 * ThreadId
+	 * ((ChipId * N1SDP_MAX_CLUSTERS_PER_CHIP + ClusterId) *
+	 * N1SDP_MAX_CPUS_PER_CLUSTER * N1SDP_MAX_PE_PER_CPU) +
+	 * (CPUId * N1SDP_MAX_PE_PER_CPU) + ThreadId
 	 *
 	 * which can be simplified as:
 	 *
-	 * ((ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER + CPUId) *
-	 * N1SDP_MAX_PE_PER_CPU) + ThreadId
+	 * (((ChipId * N1SDP_MAX_CLUSTERS_PER_CHIP + ClusterId) *
+	 * N1SDP_MAX_CPUS_PER_CLUSTER + CPUId) * N1SDP_MAX_PE_PER_CPU) +
+	 * ThreadId
 	 * ------------------------------------------------------
 	 */
 
 func plat_arm_calc_core_pos
-	mov	x3, x0
+	mov	x4, x0
 
 	/*
 	 * The MT bit in MPIDR is always set for n1sdp and the
@@ -37,15 +38,18 @@
 	 */
 
 	/* Extract individual affinity fields from MPIDR */
-	ubfx	x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
-	ubfx	x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
-	ubfx	x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+	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, #N1SDP_MAX_CLUSTERS_PER_CHIP
+	madd	x2, x3, x4, x2
 	mov	x4, #N1SDP_MAX_CPUS_PER_CLUSTER
 	madd	x1, x2, x4, x1
-	mov	x5, #N1SDP_MAX_PE_PER_CPU
-	madd	x0, x1, x5, x0
+	mov	x4, #N1SDP_MAX_PE_PER_CPU
+	madd	x0, x1, x4, x0
 	ret
 endfunc plat_arm_calc_core_pos
 
diff --git a/plat/arm/board/n1sdp/include/platform_def.h b/plat/arm/board/n1sdp/include/platform_def.h
index 7348bf5..6a309e8 100644
--- a/plat/arm/board/n1sdp/include/platform_def.h
+++ b/plat/arm/board/n1sdp/include/platform_def.h
@@ -27,16 +27,27 @@
 #define PLAT_ARM_DRAM2_BASE			ULL(0x8080000000)
 #define PLAT_ARM_DRAM2_SIZE			ULL(0xF80000000)
 
+/* N1SDP remote chip at 4 TB offset */
+#define PLAT_ARM_REMOTE_CHIP_OFFSET		(ULL(1) << 42)
+
+#define N1SDP_REMOTE_DRAM1_BASE			ARM_DRAM1_BASE + \
+						PLAT_ARM_REMOTE_CHIP_OFFSET
+#define N1SDP_REMOTE_DRAM1_SIZE			ARM_DRAM1_SIZE
+
+#define N1SDP_REMOTE_DRAM2_BASE			PLAT_ARM_DRAM2_BASE + \
+						PLAT_ARM_REMOTE_CHIP_OFFSET
+#define N1SDP_REMOTE_DRAM2_SIZE			PLAT_ARM_DRAM2_SIZE
+
 /*
  * N1SDP platform supports RDIMMs with ECC capability. To use the ECC
  * capability, the entire DDR memory space has to be zeroed out before
- * enabling the ECC bits in DMC620. The access the complete DDR memory
- * space the physical & virtual address space limits are extended to
- * 40-bits.
+ * enabling the ECC bits in DMC620. To access the complete DDR memory
+ * along with remote chip's DDR memory, which is at 4 TB offset, physical
+ * and virtual address space limits are extended to 43-bits.
  */
 #ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 40)
-#define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 40)
+#define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 43)
+#define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 43)
 #else
 #define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 32)
@@ -51,34 +62,36 @@
 #define PLAT_ARM_TRUSTED_SRAM_SIZE		0x00080000	/* 512 KB */
 #define PLAT_ARM_MAX_BL31_SIZE			0X20000
 
-
 /*******************************************************************************
  * N1SDP topology related constants
  ******************************************************************************/
-#define N1SDP_MAX_CPUS_PER_CLUSTER		2
-#define PLAT_ARM_CLUSTER_COUNT			2
-#define N1SDP_MAX_PE_PER_CPU			1
+#define N1SDP_MAX_CPUS_PER_CLUSTER		U(2)
+#define PLAT_ARM_CLUSTER_COUNT			U(2)
+#define PLAT_N1SDP_CHIP_COUNT			U(2)
+#define N1SDP_MAX_CLUSTERS_PER_CHIP		U(2)
+#define N1SDP_MAX_PE_PER_CPU			U(1)
 
-#define PLATFORM_CORE_COUNT			(PLAT_ARM_CLUSTER_COUNT *	\
+#define PLATFORM_CORE_COUNT			(PLAT_N1SDP_CHIP_COUNT *	\
+						PLAT_ARM_CLUSTER_COUNT *	\
 						N1SDP_MAX_CPUS_PER_CLUSTER *	\
 						N1SDP_MAX_PE_PER_CPU)
 
 /* System power domain level */
-#define CSS_SYSTEM_PWR_DMN_LVL			ARM_PWR_LVL2
+#define CSS_SYSTEM_PWR_DMN_LVL			ARM_PWR_LVL3
 
 /*
  * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
  * plat_arm_mmap array defined for each BL stage.
  */
-#define PLAT_ARM_MMAP_ENTRIES			6
-#define MAX_XLAT_TABLES				7
+#define PLAT_ARM_MMAP_ENTRIES			9
+#define MAX_XLAT_TABLES				10
 
 #define PLATFORM_STACK_SIZE			0x400
 
 #define PLAT_ARM_NSTIMER_FRAME_ID		0
 #define PLAT_CSS_MHU_BASE			0x45000000
 #define PLAT_MHUV2_BASE				PLAT_CSS_MHU_BASE
-#define PLAT_MAX_PWR_LVL			1
+#define PLAT_MAX_PWR_LVL			2
 
 #define PLAT_ARM_G1S_IRQS			ARM_G1S_IRQS,			\
 						CSS_IRQ_MHU
@@ -88,17 +101,36 @@
 #define PLAT_ARM_G0_IRQ_PROPS(grp)		ARM_G0_IRQ_PROPS(grp)
 
 
-#define N1SDP_DEVICE_BASE			(0x08000000)
-#define N1SDP_DEVICE_SIZE			(0x48000000)
-#define N1SDP_MAP_DEVICE			MAP_REGION_FLAT(	\
-						N1SDP_DEVICE_BASE,	\
-						N1SDP_DEVICE_SIZE,	\
-						MT_DEVICE | MT_RW | MT_SECURE)
+#define N1SDP_DEVICE_BASE			ULL(0x08000000)
+#define N1SDP_DEVICE_SIZE			ULL(0x48000000)
+#define N1SDP_REMOTE_DEVICE_BASE		N1SDP_DEVICE_BASE + \
+						PLAT_ARM_REMOTE_CHIP_OFFSET
+#define N1SDP_REMOTE_DEVICE_SIZE		N1SDP_DEVICE_SIZE
+
+#define N1SDP_MAP_DEVICE		MAP_REGION_FLAT(	\
+					N1SDP_DEVICE_BASE,	\
+					N1SDP_DEVICE_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define ARM_MAP_DRAM1			MAP_REGION_FLAT(	\
+					ARM_DRAM1_BASE,		\
+					ARM_DRAM1_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define N1SDP_MAP_REMOTE_DEVICE		MAP_REGION_FLAT(		\
+					N1SDP_REMOTE_DEVICE_BASE,	\
+					N1SDP_REMOTE_DEVICE_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define N1SDP_MAP_REMOTE_DRAM1		MAP_REGION_FLAT(		\
+					N1SDP_REMOTE_DRAM1_BASE,	\
+					N1SDP_REMOTE_DRAM1_SIZE,	\
+					MT_MEMORY | MT_RW | MT_NS)
 
-#define ARM_MAP_DRAM1				MAP_REGION_FLAT(	\
-						ARM_DRAM1_BASE,		\
-						ARM_DRAM1_SIZE,		\
-						MT_MEMORY | MT_RW | MT_NS)
+#define N1SDP_MAP_REMOTE_DRAM2		MAP_REGION_FLAT(		\
+					N1SDP_REMOTE_DRAM2_BASE,	\
+					N1SDP_REMOTE_DRAM2_SIZE,	\
+					MT_MEMORY | MT_RW | MT_NS)
 
 /* GIC related constants */
 #define PLAT_ARM_GICD_BASE			0x30000000
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
index 632af7b..4f158ee 100644
--- a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <drivers/arm/css/css_mhu_doorbell.h>
 #include <drivers/arm/css/scmi.h>
 #include <drivers/arm/css/sds.h>
+#include <drivers/arm/gic600_multichip.h>
 #include <common/debug.h>
 #include <lib/mmio.h>
 #include <lib/utils.h>
@@ -17,14 +18,22 @@
 #include "n1sdp_def.h"
 
 /*
- * Memory information structure stored in SDS.
- * This structure holds the total DDR memory size which will be
- * used when zeroing out the entire DDR memory before enabling
- * the ECC capability in DMCs.
+ * Platform information structure stored in SDS.
+ * This structure holds information about platform's DDR
+ * size which will be used to zero out the memory before
+ * enabling the ECC capability as well as information
+ * about multichip setup
+ * 	- multichip mode
+ * 	- slave_count
+ * 	- Local DDR size in GB, DDR memory in master board
+ * 	- Remote DDR size in GB, DDR memory in slave board
  */
-struct n1sdp_mem_info {
-	uint32_t ddr_size_gb;
-};
+struct n1sdp_plat_info {
+	bool multichip_mode;
+	uint8_t slave_count;
+	uint8_t local_ddr_size;
+	uint8_t remote_ddr_size;
+} __packed;
 
 /*
  * BL33 image information structure stored in SDS.
@@ -38,13 +47,33 @@
 };
 
 static scmi_channel_plat_info_t n1sdp_scmi_plat_info = {
-		.scmi_mbx_mem = N1SDP_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,
+	.scmi_mbx_mem = N1SDP_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 struct gic600_multichip_data n1sdp_multichip_data __init = {
+	.rt_owner_base = PLAT_ARM_GICD_BASE,
+	.rt_owner = 0,
+	.chip_count = 1,
+	.chip_addrs = {
+		PLAT_ARM_GICD_BASE >> 16,
+		PLAT_ARM_GICD_BASE >> 16
+	},
+	.spi_ids = {
+		{32, 255},
+		{0, 0}
+	}
 };
 
+static uintptr_t n1sdp_multichip_gicr_frames[3] = {
+	PLAT_ARM_GICR_BASE,
+	PLAT_ARM_GICR_BASE + PLAT_ARM_REMOTE_CHIP_OFFSET,
+	0
+};
+
 scmi_channel_plat_info_t *plat_css_get_scmi_info()
 {
 	return &n1sdp_scmi_plat_info;
@@ -66,7 +95,7 @@
  * from IOFPGA-DDR3 memory to main DDR4 memory.
  */
 
-void dmc_ecc_setup(uint32_t ddr_size_gb)
+void dmc_ecc_setup(uint8_t ddr_size_gb)
 {
 	uint64_t dram2_size;
 
@@ -93,6 +122,38 @@
 	mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
 }
 
+void remote_dmc_ecc_setup(uint8_t remote_ddr_size)
+{
+	uint64_t remote_dram2_size;
+
+	remote_dram2_size = (remote_ddr_size * 1024UL * 1024UL * 1024UL) -
+				N1SDP_REMOTE_DRAM1_SIZE;
+	/* multichip setup */
+	INFO("Zeroing remote DDR memories\n");
+	zero_normalmem((void *)N1SDP_REMOTE_DRAM1_BASE,
+			N1SDP_REMOTE_DRAM1_SIZE);
+	flush_dcache_range(N1SDP_REMOTE_DRAM1_BASE, N1SDP_REMOTE_DRAM1_SIZE);
+	zero_normalmem((void *)N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
+	flush_dcache_range(N1SDP_REMOTE_DRAM2_BASE, remote_dram2_size);
+
+	INFO("Enabling ECC on remote DMCs\n");
+	/* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
+	mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG,
+			N1SDP_DMC_MEMC_CMD_CONFIG);
+	mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG,
+			N1SDP_DMC_MEMC_CMD_CONFIG);
+
+	/* Enable ECC in DMCs */
+	mmio_setbits_32(N1SDP_REMOTE_DMC0_ERR0CTLR0_REG,
+			N1SDP_DMC_ERR0CTLR0_ECC_EN);
+	mmio_setbits_32(N1SDP_REMOTE_DMC1_ERR0CTLR0_REG,
+			N1SDP_DMC_ERR0CTLR0_ECC_EN);
+
+	/* Set DMCs to READY state */
+	mmio_write_32(N1SDP_REMOTE_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
+	mmio_write_32(N1SDP_REMOTE_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
+}
+
 void copy_bl33(uint32_t src, uint32_t dst, uint32_t size)
 {
 	uint32_t i;
@@ -109,30 +170,53 @@
 	}
 }
 
+void n1sdp_bl31_multichip_setup(void)
+{
+	plat_arm_override_gicr_frames(n1sdp_multichip_gicr_frames);
+	gic600_multichip_init(&n1sdp_multichip_data);
+}
+
 void bl31_platform_setup(void)
 {
 	int ret;
-	struct n1sdp_mem_info mem_info;
+	struct n1sdp_plat_info plat_info;
 	struct n1sdp_bl33_info bl33_info;
 
-	arm_bl31_platform_setup();
-
 	ret = sds_init();
 	if (ret != SDS_OK) {
 		ERROR("SDS initialization failed\n");
 		panic();
 	}
 
-	ret = sds_struct_read(N1SDP_SDS_MEM_INFO_STRUCT_ID,
-				N1SDP_SDS_MEM_INFO_OFFSET,
-				&mem_info,
-				N1SDP_SDS_MEM_INFO_SIZE,
+	ret = sds_struct_read(N1SDP_SDS_PLATFORM_INFO_STRUCT_ID,
+				N1SDP_SDS_PLATFORM_INFO_OFFSET,
+				&plat_info,
+				N1SDP_SDS_PLATFORM_INFO_SIZE,
 				SDS_ACCESS_MODE_NON_CACHED);
 	if (ret != SDS_OK) {
-		ERROR("Error getting memory info from SDS\n");
+		ERROR("Error getting platform info from SDS\n");
 		panic();
 	}
-	dmc_ecc_setup(mem_info.ddr_size_gb);
+	/* Validate plat_info SDS */
+	if ((plat_info.local_ddr_size == 0)
+		|| (plat_info.local_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+		|| (plat_info.remote_ddr_size > N1SDP_MAX_DDR_CAPACITY_GB)
+		|| (plat_info.slave_count > N1SDP_MAX_SLAVE_COUNT)) {
+		ERROR("platform info SDS is corrupted\n");
+		panic();
+	}
+
+	if (plat_info.multichip_mode) {
+		n1sdp_multichip_data.chip_count = plat_info.slave_count + 1;
+		n1sdp_bl31_multichip_setup();
+	}
+	arm_bl31_platform_setup();
+
+	dmc_ecc_setup(plat_info.local_ddr_size);
+
+	/* Check if remote memory is present */
+	if ((plat_info.multichip_mode) && (plat_info.remote_ddr_size != 0))
+		remote_dmc_ecc_setup(plat_info.remote_ddr_size);
 
 	ret = sds_struct_read(N1SDP_SDS_BL33_INFO_STRUCT_ID,
 				N1SDP_SDS_BL33_INFO_OFFSET,
@@ -147,11 +231,11 @@
 			bl33_info.bl33_dst_addr,
 			bl33_info.bl33_size);
 	/*
-	 * Pass DDR memory size info to BL33. This method is followed as
+	 * Pass platform information to BL33. This method is followed as
 	 * currently there is no BL1/BL2 involved in boot flow of N1SDP.
 	 * When TBBR is implemented for N1SDP, this method should be removed
-	 * and DDR memory size shoule be passed to BL33 using NT_FW_CONFIG
+	 * and platform information should be passed to BL33 using NT_FW_CONFIG
 	 * passing mechanism.
 	 */
-	mmio_write_32(N1SDP_DDR_MEM_INFO_BASE, mem_info.ddr_size_gb);
+	mmio_write_32(N1SDP_PLATFORM_INFO_BASE, *(uint32_t *)&plat_info);
 }
diff --git a/plat/arm/board/n1sdp/n1sdp_def.h b/plat/arm/board/n1sdp/n1sdp_def.h
index d43c5a4..30e29a7 100644
--- a/plat/arm/board/n1sdp/n1sdp_def.h
+++ b/plat/arm/board/n1sdp/n1sdp_def.h
@@ -15,10 +15,12 @@
 						N1SDP_NS_SRAM_SIZE,	\
 						MT_DEVICE | MT_RW | MT_SECURE)
 
-/* SDS memory information defines */
-#define N1SDP_SDS_MEM_INFO_STRUCT_ID		8
-#define N1SDP_SDS_MEM_INFO_OFFSET		0
-#define N1SDP_SDS_MEM_INFO_SIZE			4
+/* SDS Platform information defines */
+#define N1SDP_SDS_PLATFORM_INFO_STRUCT_ID	8
+#define N1SDP_SDS_PLATFORM_INFO_OFFSET		0
+#define N1SDP_SDS_PLATFORM_INFO_SIZE		4
+#define N1SDP_MAX_DDR_CAPACITY_GB		64
+#define N1SDP_MAX_SLAVE_COUNT			16
 
 /* SDS BL33 image information defines */
 #define N1SDP_SDS_BL33_INFO_STRUCT_ID		9
@@ -33,6 +35,18 @@
 #define N1SDP_DMC0_ERR0CTLR0_REG		0x4E000708
 #define N1SDP_DMC1_ERR0CTLR0_REG		0x4E100708
 
+/* Remote DMC memory command registers */
+#define N1SDP_REMOTE_DMC0_MEMC_CMD_REG		PLAT_ARM_REMOTE_CHIP_OFFSET +\
+							N1SDP_DMC0_MEMC_CMD_REG
+#define N1SDP_REMOTE_DMC1_MEMC_CMD_REG		PLAT_ARM_REMOTE_CHIP_OFFSET +\
+							N1SDP_DMC1_MEMC_CMD_REG
+
+/* Remote DMC ERR0CTLR0 registers */
+#define N1SDP_REMOTE_DMC0_ERR0CTLR0_REG		PLAT_ARM_REMOTE_CHIP_OFFSET +\
+							N1SDP_DMC0_ERR0CTLR0_REG
+#define N1SDP_REMOTE_DMC1_ERR0CTLR0_REG		PLAT_ARM_REMOTE_CHIP_OFFSET +\
+							N1SDP_DMC1_ERR0CTLR0_REG
+
 /* DMC memory commands */
 #define N1SDP_DMC_MEMC_CMD_CONFIG		0
 #define N1SDP_DMC_MEMC_CMD_READY		3
@@ -40,7 +54,7 @@
 /* DMC ECC enable bit in ERR0CTLR0 register */
 #define N1SDP_DMC_ERR0CTLR0_ECC_EN		0x1
 
-/* Base address of non-secure SRAM where DDR memory size will be filled */
-#define N1SDP_DDR_MEM_INFO_BASE			0x06008000
+/* Base address of non-secure SRAM where Platform information will be filled */
+#define N1SDP_PLATFORM_INFO_BASE		0x06008000
 
 #endif /* N1SDP_DEF_H */
diff --git a/plat/arm/board/n1sdp/n1sdp_plat.c b/plat/arm/board/n1sdp/n1sdp_plat.c
index a32ca72..951a562 100644
--- a/plat/arm/board/n1sdp/n1sdp_plat.c
+++ b/plat/arm/board/n1sdp/n1sdp_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,6 +25,9 @@
 	N1SDP_MAP_NS_SRAM,
 	ARM_MAP_DRAM1,
 	ARM_MAP_DRAM2,
+	N1SDP_MAP_REMOTE_DEVICE,
+	N1SDP_MAP_REMOTE_DRAM1,
+	N1SDP_MAP_REMOTE_DRAM2,
 	{0}
 };
 
diff --git a/plat/arm/board/n1sdp/n1sdp_topology.c b/plat/arm/board/n1sdp/n1sdp_topology.c
index edf1170..5c2db71 100644
--- a/plat/arm/board/n1sdp/n1sdp_topology.c
+++ b/plat/arm/board/n1sdp/n1sdp_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,7 +19,11 @@
  * indices returned by plat_core_pos_by_mpidr().
  */
 const unsigned char n1sdp_pd_tree_desc[] = {
+	PLAT_N1SDP_CHIP_COUNT,
 	PLAT_ARM_CLUSTER_COUNT,
+	PLAT_ARM_CLUSTER_COUNT,
+	N1SDP_MAX_CPUS_PER_CLUSTER,
+	N1SDP_MAX_CPUS_PER_CLUSTER,
 	N1SDP_MAX_CPUS_PER_CLUSTER,
 	N1SDP_MAX_CPUS_PER_CLUSTER
 };
@@ -52,4 +56,4 @@
  * to the SCMI power domain ID implemented by SCP.
  ******************************************************************************/
 const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
-	0, 1, 2, 3};
+	0, 1, 2, 3, 4, 5, 6, 7};
diff --git a/plat/arm/board/n1sdp/platform.mk b/plat/arm/board/n1sdp/platform.mk
index 986bd70..8816670 100644
--- a/plat/arm/board/n1sdp/platform.mk
+++ b/plat/arm/board/n1sdp/platform.mk
@@ -18,6 +18,7 @@
 N1SDP_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
 				drivers/arm/gic/v3/gicv3_main.c		\
 				drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/gic600_multichip.c	\
 				plat/common/plat_gicv3.c		\
 				plat/arm/common/arm_gicv3.c		\
 				drivers/arm/gic/v3/gic600.c
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
index fef5376..cfc5359 100644
--- a/plat/arm/common/arm_gicv3.c
+++ b/plat/arm/common/arm_gicv3.c
@@ -28,6 +28,15 @@
 /* The GICv3 driver only needs to be initialized in EL3 */
 static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
 
+/* Default GICR base address to be used for GICR probe. */
+static const uintptr_t gicr_base_addrs[2] = {
+	PLAT_ARM_GICR_BASE,	/* GICR Base address of the primary CPU */
+	0U			/* Zero Termination */
+};
+
+/* List of zero terminated GICR frame addresses which CPUs will probe */
+static const uintptr_t *gicr_frames = gicr_base_addrs;
+
 static const interrupt_prop_t arm_interrupt_props[] = {
 	PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
 	PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0)
@@ -76,6 +85,18 @@
 	.mpidr_to_core_pos = arm_gicv3_mpidr_hash
 };
 
+/*
+ * By default, gicr_frames will be pointing to gicr_base_addrs. If
+ * the platform supports a non-contiguous GICR frames (GICR frames located
+ * at uneven offset), plat_arm_override_gicr_frames function can be used by
+ * such platform to override the gicr_frames.
+ */
+void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames)
+{
+	assert(plat_gicr_frames != NULL);
+	gicr_frames = plat_gicr_frames;
+}
+
 void __init plat_arm_gic_driver_init(void)
 {
 	/*
@@ -88,7 +109,7 @@
 	(defined(__aarch64__) && defined(IMAGE_BL31))
 	gicv3_driver_init(&arm_gic_data);
 
-	if (gicv3_rdistif_probe(PLAT_ARM_GICR_BASE) == -1) {
+	if (gicv3_rdistif_probe(gicr_base_addrs[0]) == -1) {
 		ERROR("No GICR base frame found for Primary CPU\n");
 		panic();
 	}
@@ -124,14 +145,23 @@
 /******************************************************************************
  * ARM common helper function to iterate over all GICR frames and discover the
  * corresponding per-cpu redistributor frame as well as initialize the
- * corresponding interface in GICv3. At the moment, Arm platforms do not have
- * non-contiguous GICR frames.
+ * corresponding interface in GICv3.
  *****************************************************************************/
 void plat_arm_gic_pcpu_init(void)
 {
 	int result;
+	const uintptr_t *plat_gicr_frames = gicr_frames;
+
+	do {
+		result = gicv3_rdistif_probe(*plat_gicr_frames);
+
+		/* If the probe is successful, no need to proceed further */
+		if (result == 0)
+			break;
+
+		plat_gicr_frames++;
+	} while (*plat_gicr_frames != 0U);
 
-	result = gicv3_rdistif_probe(PLAT_ARM_GICR_BASE);
 	if (result == -1) {
 		ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
 		panic();
diff --git a/plat/ti/k3/common/plat_common.mk b/plat/ti/k3/common/plat_common.mk
index 20a94ef..7956497 100644
--- a/plat/ti/k3/common/plat_common.mk
+++ b/plat/ti/k3/common/plat_common.mk
@@ -31,6 +31,9 @@
 # Split out RO data into a non-executable section
 SEPARATE_CODE_AND_RODATA :=    1
 
+# Generate a Position Independent Executable
+ENABLE_PIE		:=	1
+
 TI_16550_MDR_QUIRK	:=	1
 $(eval $(call add_define,TI_16550_MDR_QUIRK))