board/rdn1edge: add support for dual-chip configuration

RD-N1-Edge based platforms can operate in dual-chip configuration
wherein two rdn1edge SoCs are connected through a high speed coherent
CCIX link.

This patch adds a function to check if the RD-N1-Edge platform is
operating in multi-chip mode by reading the SID register's NODE_ID
value. If operating in multi-chip mode, initialize GIC-600 multi-chip
operation by overriding the default GICR frames with array of GICR
frames and setting the chip 0 as routing table owner.

The address space of the second RD-N1-Edge chip (chip 1) starts from the
address 4TB. So increase the physical and virtual address space size to
43 bits to accommodate the multi-chip configuration. If the multi-chip
mode configuration is detected, dynamically add mmap entry for the
peripherals memory region of the second RD-N1-Edge SoC. This is required
to let the BL31 platform setup stage to configure the devices in the
second chip.

PLATFORM_CORE_COUNT macro is set to be multiple of CSS_SGI_CHIP_COUNT
and topology changes are added to represent the dual-chip configuration.

In order the build the dual-chip platform, CSS_SGI_CHIP_COUNT macro
should be set to 2:
export CROSS_COMPILE=<path-to-cross-compiler>
make PLAT=rdn1edge CSS_SGI_CHIP_COUNT=2 ARCH=aarch64 all

Change-Id: I576cdaf71f0b0e41b9a9181fa4feb7091f8c7bb4
Signed-off-by: Aditya Angadi <aditya.angadi@arm.com>
Signed-off-by: Vijayenthiran Subramaniam <vijayenthiran.subramaniam@arm.com>
diff --git a/plat/arm/board/rdn1edge/include/platform_def.h b/plat/arm/board/rdn1edge/include/platform_def.h
index a00df7d..46555f2 100644
--- a/plat/arm/board/rdn1edge/include/platform_def.h
+++ b/plat/arm/board/rdn1edge/include/platform_def.h
@@ -26,12 +26,15 @@
 
 #define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
 
+/* Virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xc0000000)
+
 /*
  * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
  */
 #ifdef __aarch64__
-#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
-#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#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)
diff --git a/plat/arm/board/rdn1edge/platform.mk b/plat/arm/board/rdn1edge/platform.mk
index 90e9338..04f70f3 100644
--- a/plat/arm/board/rdn1edge/platform.mk
+++ b/plat/arm/board/rdn1edge/platform.mk
@@ -26,6 +26,7 @@
 				${RDN1EDGE_BASE}/rdn1edge_plat.c	\
 				${RDN1EDGE_BASE}/rdn1edge_topology.c	\
 				drivers/cfi/v2m/v2m_flash.c		\
+				drivers/arm/gic/v3/gic600_multichip.c	\
 				lib/utils/mem_region.c			\
 				plat/arm/common/arm_nor_psci_mem_protect.c
 
@@ -34,6 +35,9 @@
 BL2_SOURCES		+=	${RDN1EDGE_BASE}/rdn1edge_trusted_boot.c
 endif
 
+# Enable dynamic addition of MMAP regions in BL31
+BL31_CFLAGS		+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+
 # Add the FDT_SOURCES and options for Dynamic Config
 FDT_SOURCES		+=	${RDN1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts
 TB_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
@@ -47,9 +51,9 @@
 # Add the NT_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config))
 
-ifneq ($(CSS_SGI_CHIP_COUNT),1)
- $(error  "Chip count for RDN1Edge should be 1, currently set to \
-   ${CSS_SGI_CHIP_COUNT}.")
+ifneq ($(CSS_SGI_CHIP_COUNT),$(filter $(CSS_SGI_CHIP_COUNT),1 2))
+ $(error  "Chip count for RDN1Edge platform should either 1 or 2, currently \
+   set to ${CSS_SGI_CHIP_COUNT}.")
 endif
 
 override CTX_INCLUDE_AARCH32_REGS	:= 0
diff --git a/plat/arm/board/rdn1edge/rdn1edge_plat.c b/plat/arm/board/rdn1edge/rdn1edge_plat.c
index f7c7e9b..f62c6f4 100644
--- a/plat/arm/board/rdn1edge/rdn1edge_plat.c
+++ b/plat/arm/board/rdn1edge/rdn1edge_plat.c
@@ -4,9 +4,42 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <common/debug.h>
+#include <drivers/arm/gic600_multichip.h>
+#include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
+#include <sgi_base_platform_def.h>
 #include <sgi_plat.h>
 
+#if defined(IMAGE_BL31)
+static const mmap_region_t rdn1edge_dynamic_mmap[] = {
+	ARM_MAP_SHARED_RAM_REMOTE_CHIP(1),
+	CSS_SGI_MAP_DEVICE_REMOTE_CHIP(1),
+	SOC_CSS_MAP_DEVICE_REMOTE_CHIP(1)
+};
+
+static struct gic600_multichip_data rdn1e1_multichip_data __init = {
+	.rt_owner_base = PLAT_ARM_GICD_BASE,
+	.rt_owner = 0,
+	.chip_count = CSS_SGI_CHIP_COUNT,
+	.chip_addrs = {
+		PLAT_ARM_GICD_BASE >> 16,
+		(PLAT_ARM_GICD_BASE + CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+	},
+	.spi_ids = {
+		{32, 255},
+		{0, 0}
+	}
+};
+
+static uintptr_t rdn1e1_multichip_gicr_frames[] = {
+	PLAT_ARM_GICR_BASE,				/* Chip 0's GICR Base */
+	PLAT_ARM_GICR_BASE +
+		CSS_SGI_REMOTE_CHIP_MEM_OFFSET(1),	/* Chip 1's GICR BASE */
+	UL(0)						/* Zero Termination */
+};
+#endif /* IMAGE_BL31 */
+
 unsigned int plat_arm_sgi_get_platform_id(void)
 {
 	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
@@ -24,7 +57,41 @@
 			SID_MULTI_CHIP_MODE_MASK) >> SID_MULTI_CHIP_MODE_SHIFT;
 }
 
+/*
+ * IMAGE_BL31 macro is added to build bl31_platform_setup function only for BL31
+ * because PLAT_XLAT_TABLES_DYNAMIC macro is set to build only for BL31 and not
+ * for other stages.
+ */
+#if defined(IMAGE_BL31)
 void bl31_platform_setup(void)
 {
+	int i, ret;
+
+	if (plat_arm_sgi_get_multi_chip_mode() == 0 && CSS_SGI_CHIP_COUNT > 1) {
+		ERROR("Chip Count is set to %d but multi-chip mode not enabled\n",
+				CSS_SGI_CHIP_COUNT);
+		panic();
+	} else if (plat_arm_sgi_get_multi_chip_mode() == 1 &&
+			CSS_SGI_CHIP_COUNT > 1) {
+		INFO("Enabling support for multi-chip in RD-N1-Edge\n");
+
+		for (i = 0; i < ARRAY_SIZE(rdn1edge_dynamic_mmap); i++) {
+			ret = mmap_add_dynamic_region(
+					rdn1edge_dynamic_mmap[i].base_pa,
+					rdn1edge_dynamic_mmap[i].base_va,
+					rdn1edge_dynamic_mmap[i].size,
+					rdn1edge_dynamic_mmap[i].attr
+					);
+			if (ret != 0) {
+				ERROR("Failed to add dynamic mmap entry\n");
+				panic();
+			}
+		}
+
+		plat_arm_override_gicr_frames(rdn1e1_multichip_gicr_frames);
+		gic600_multichip_init(&rdn1e1_multichip_data);
+	}
+
 	sgi_bl31_common_platform_setup();
 }
+#endif /* IMAGE_BL31 */
diff --git a/plat/arm/board/rdn1edge/rdn1edge_topology.c b/plat/arm/board/rdn1edge/rdn1edge_topology.c
index 687ae35..5bbea69 100644
--- a/plat/arm/board/rdn1edge/rdn1edge_topology.c
+++ b/plat/arm/board/rdn1edge/rdn1edge_topology.c
@@ -5,14 +5,19 @@
  */
 
 #include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
 
 /******************************************************************************
  * The power domain tree descriptor.
  ******************************************************************************/
 static const unsigned char rdn1edge_pd_tree_desc[] = {
-	PLAT_ARM_CLUSTER_COUNT,
+	(PLAT_ARM_CLUSTER_COUNT) * (CSS_SGI_CHIP_COUNT),
+	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+#if (CSS_SGI_CHIP_COUNT > 1)
 	CSS_SGI_MAX_CPUS_PER_CLUSTER,
 	CSS_SGI_MAX_CPUS_PER_CLUSTER
+#endif
 };
 
 /*******************************************************************************
@@ -28,5 +33,22 @@
  * to the SCMI power domain ID implemented by SCP.
  ******************************************************************************/
 const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[] = {
-	0, 1, 2, 3, 4, 5, 6, 7
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x0)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x1)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x2)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x3)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x4)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x5)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x6)),
+	(SET_SCMI_CHANNEL_ID(0x0) | SET_SCMI_DOMAIN_ID(0x7)),
+#if (CSS_SGI_CHIP_COUNT > 1)
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x0)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x1)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x2)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x3)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x4)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x5)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x6)),
+	(SET_SCMI_CHANNEL_ID(0x1) | SET_SCMI_DOMAIN_ID(0x7)),
+#endif
 };
diff --git a/plat/arm/css/sgi/include/sgi_base_platform_def.h b/plat/arm/css/sgi/include/sgi_base_platform_def.h
index cc5ead8..7eb3d3c 100644
--- a/plat/arm/css/sgi/include/sgi_base_platform_def.h
+++ b/plat/arm/css/sgi/include/sgi_base_platform_def.h
@@ -17,8 +17,9 @@
 #include <plat/arm/soc/common/soc_css_def.h>
 #include <plat/common/common_def.h>
 
-#define PLATFORM_CORE_COUNT		(PLAT_ARM_CLUSTER_COUNT *	\
-					CSS_SGI_MAX_CPUS_PER_CLUSTER * \
+#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	0x00040000	/* 256 KB */
@@ -38,14 +39,14 @@
 #  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
 # else
 #  define PLAT_ARM_MMAP_ENTRIES		8
-#  define MAX_XLAT_TABLES		5
+#  define MAX_XLAT_TABLES		8
 # endif
 #elif defined(IMAGE_BL32)
 # define PLAT_ARM_MMAP_ENTRIES		8
 # define MAX_XLAT_TABLES		5
 #elif !USE_ROMLIB
 # define PLAT_ARM_MMAP_ENTRIES		11
-# define MAX_XLAT_TABLES		5
+# define MAX_XLAT_TABLES		7
 #else
 # define PLAT_ARM_MMAP_ENTRIES		12
 # define MAX_XLAT_TABLES		6
diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/css/sgi/sgi_bl31_setup.c
index 3d2d933..f5d0f41 100644
--- a/plat/arm/css/sgi/sgi_bl31_setup.c
+++ b/plat/arm/css/sgi/sgi_bl31_setup.c
@@ -28,18 +28,56 @@
 		.ring_doorbell = &mhu_ring_doorbell,
 };
 
-static scmi_channel_plat_info_t rd_n1e1_edge_scmi_plat_info = {
+static scmi_channel_plat_info_t rd_n1e1_edge_scmi_plat_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(int channel_id)
 {
-	if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM)
-		return &rd_n1e1_edge_scmi_plat_info;
+	if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) {
+		if (channel_id >= sizeof(rd_n1e1_edge_scmi_plat_info))
+			panic();
+		return &rd_n1e1_edge_scmi_plat_info[channel_id];
+	}
 	else if (sgi_plat_info.platform_id == SGI575_SSC_VER_PART_NUM)
 		return &sgi575_scmi_plat_info;
 	else