FVP: Support Base FVP RevC

Revision C of the Base FVP has the same memory map as earlier revisions,
but has the following differences:

  - Implements CCI550 instead of CCI400,
  - Has a single instantiation of SMMUv3,
  - CPU MPIDs are shifted left by one level, and has MT bit set in them.

The correct interconnect to program is chosen at run time based on the
FVP revision. Therefore, this patch implements FVP functions for
interconnect programming, rather than depending on ARM generic ones. The
macros used have been renamed to reflect this change.

Additionally, this patch initializes SMMUv3 as part of FVP early
platform setup.

New ARM config flags are introduced for feature queries at run time.

Change-Id: Ic7b7f080953a51fceaf62ce7daa6de0573801f09
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
diff --git a/include/plat/arm/common/arm_config.h b/include/plat/arm/common/arm_config.h
index 2ab7bf2..02e04fd 100644
--- a/include/plat/arm/common/arm_config.h
+++ b/include/plat/arm/common/arm_config.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,14 +7,20 @@
 #define __ARM_CONFIG_H__
 
 #include <stdint.h>
+#include <utils_def.h>
 
 enum arm_config_flags {
 	/* Whether Base memory map is in use */
-	ARM_CONFIG_BASE_MMAP		= 0x1,
-	/* Whether interconnect should be enabled */
-	ARM_CONFIG_HAS_INTERCONNECT	= 0x2,
+	ARM_CONFIG_BASE_MMAP		= BIT(1),
 	/* Whether TZC should be configured */
-	ARM_CONFIG_HAS_TZC		= 0x4
+	ARM_CONFIG_HAS_TZC		= BIT(2),
+	/* FVP model has shifted affinity */
+	ARM_CONFIG_FVP_SHIFTED_AFF	= BIT(3),
+	/* FVP model has SMMUv3 affinity */
+	ARM_CONFIG_FVP_HAS_SMMUV3	= BIT(4),
+	/* FVP model has CCI (400 or 500/550) devices */
+	ARM_CONFIG_FVP_HAS_CCI400	= BIT(5),
+	ARM_CONFIG_FVP_HAS_CCI5XX	= BIT(6),
 };
 
 typedef struct arm_config {
diff --git a/plat/arm/board/fvp/fvp_bl31_setup.c b/plat/arm/board/fvp/fvp_bl31_setup.c
index 52a4432..181c923 100644
--- a/plat/arm/board/fvp/fvp_bl31_setup.c
+++ b/plat/arm/board/fvp/fvp_bl31_setup.c
@@ -1,10 +1,12 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <arm_config.h>
 #include <plat_arm.h>
+#include <smmu_v3.h>
 #include "fvp_private.h"
 
 #if LOAD_IMAGE_V2
@@ -34,4 +36,8 @@
 	 * FVP PSCI code will enable coherency for other clusters.
 	 */
 	fvp_interconnect_enable();
+
+	/* On FVP RevC, intialize SMMUv3 */
+	if (arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3)
+		smmuv3_init(PLAT_FVP_SMMUV3_BASE);
 }
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 2f5d7fc..c1dcc02 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -1,11 +1,13 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <arm_config.h>
 #include <arm_def.h>
+#include <assert.h>
+#include <cci.h>
 #include <ccn.h>
 #include <debug.h>
 #include <gicv2.h>
@@ -118,6 +120,30 @@
 
 ARM_CASSERT_MMAP
 
+#if FVP_INTERCONNECT_DRIVER != FVP_CCN
+static const int fvp_cci400_map[] = {
+	PLAT_FVP_CCI400_CLUS0_SL_PORT,
+	PLAT_FVP_CCI400_CLUS1_SL_PORT,
+};
+
+static const int fvp_cci5xx_map[] = {
+	PLAT_FVP_CCI5XX_CLUS0_SL_PORT,
+	PLAT_FVP_CCI5XX_CLUS1_SL_PORT,
+};
+
+static unsigned int get_interconnect_master(void)
+{
+	unsigned int master;
+	u_register_t mpidr;
+
+	mpidr = read_mpidr_el1();
+	master = (arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) ?
+		MPIDR_AFFLVL2_VAL(mpidr) : MPIDR_AFFLVL1_VAL(mpidr);
+
+	assert(master < FVP_CLUSTER_COUNT);
+	return master;
+}
+#endif
 
 /*******************************************************************************
  * A single boot loader stack is expected to work on both the Foundation FVP
@@ -182,8 +208,7 @@
 		}
 		break;
 	case HBI_BASE_FVP:
-		arm_config.flags |= ARM_CONFIG_BASE_MMAP |
-			ARM_CONFIG_HAS_INTERCONNECT | ARM_CONFIG_HAS_TZC;
+		arm_config.flags |= (ARM_CONFIG_BASE_MMAP | ARM_CONFIG_HAS_TZC);
 
 		/*
 		 * Check for supported revisions
@@ -191,6 +216,12 @@
 		 */
 		switch (rev) {
 		case REV_BASE_FVP_V0:
+			arm_config.flags |= ARM_CONFIG_FVP_HAS_CCI400;
+			break;
+		case REV_BASE_FVP_REVC:
+			arm_config.flags |= (ARM_CONFIG_FVP_SHIFTED_AFF |
+					ARM_CONFIG_FVP_HAS_SMMUV3 |
+					ARM_CONFIG_FVP_HAS_CCI5XX);
 			break;
 		default:
 			WARN("Unrecognized Base FVP revision %x\n", rev);
@@ -206,26 +237,67 @@
 
 void fvp_interconnect_init(void)
 {
-	if (arm_config.flags & ARM_CONFIG_HAS_INTERCONNECT) {
 #if FVP_INTERCONNECT_DRIVER == FVP_CCN
-		if (ccn_get_part0_id(PLAT_ARM_CCN_BASE) != CCN_502_PART0_ID) {
-			ERROR("Unrecognized CCN variant detected. Only CCN-502"
-					" is supported");
-			panic();
-		}
-#endif
-		plat_arm_interconnect_init();
+	if (ccn_get_part0_id(PLAT_ARM_CCN_BASE) != CCN_502_PART0_ID) {
+		ERROR("Unrecognized CCN variant detected. Only CCN-502"
+				" is supported");
+		panic();
+	}
+
+	plat_arm_interconnect_init();
+#else
+	uintptr_t cci_base = 0;
+	const int *cci_map = 0;
+	unsigned int map_size = 0;
+
+	if (!(arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 |
+				ARM_CONFIG_FVP_HAS_CCI5XX))) {
+		return;
+	}
+
+	/* Initialize the right interconnect */
+	if (arm_config.flags & ARM_CONFIG_FVP_HAS_CCI5XX) {
+		cci_base = PLAT_FVP_CCI5XX_BASE;
+		cci_map = fvp_cci5xx_map;
+		map_size = ARRAY_SIZE(fvp_cci5xx_map);
+	} else if (arm_config.flags & ARM_CONFIG_FVP_HAS_CCI400) {
+		cci_base = PLAT_FVP_CCI400_BASE;
+		cci_map = fvp_cci400_map;
+		map_size = ARRAY_SIZE(fvp_cci400_map);
 	}
+
+	assert(cci_base);
+	assert(cci_map);
+	cci_init(cci_base, cci_map, map_size);
+#endif
 }
 
 void fvp_interconnect_enable(void)
 {
-	if (arm_config.flags & ARM_CONFIG_HAS_INTERCONNECT)
-		plat_arm_interconnect_enter_coherency();
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+	plat_arm_interconnect_enter_coherency();
+#else
+	unsigned int master;
+
+	if (arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 |
+				ARM_CONFIG_FVP_HAS_CCI5XX)) {
+		master = get_interconnect_master();
+		cci_enable_snoop_dvm_reqs(master);
+	}
+#endif
 }
 
 void fvp_interconnect_disable(void)
 {
-	if (arm_config.flags & ARM_CONFIG_HAS_INTERCONNECT)
-		plat_arm_interconnect_exit_coherency();
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+	plat_arm_interconnect_exit_coherency();
+#else
+	unsigned int master;
+
+	if (arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 |
+				ARM_CONFIG_FVP_HAS_CCI5XX)) {
+		master = get_interconnect_master();
+		cci_disable_snoop_dvm_reqs(master);
+	}
+#endif
 }
diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h
index 84e790b..a430bca 100644
--- a/plat/arm/board/fvp/fvp_def.h
+++ b/plat/arm/board/fvp/fvp_def.h
@@ -78,6 +78,7 @@
 /* Constants to distinguish FVP type */
 #define HBI_BASE_FVP			0x020
 #define REV_BASE_FVP_V0			0x0
+#define REV_BASE_FVP_REVC		0x2
 
 #define HBI_FOUNDATION_FVP		0x010
 #define REV_FOUNDATION_FVP_V2_0		0x0
diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c
index 848aaf8..cf1492b 100644
--- a/plat/arm/board/fvp/fvp_topology.c
+++ b/plat/arm/board/fvp/fvp_topology.c
@@ -56,6 +56,26 @@
  ******************************************************************************/
 int plat_core_pos_by_mpidr(u_register_t mpidr)
 {
+	unsigned int clus_id, cpu_id, thread_id;
+
+	/* Validate affinity fields */
+	if (arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) {
+		thread_id = MPIDR_AFFLVL0_VAL(mpidr);
+		cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
+		clus_id = MPIDR_AFFLVL2_VAL(mpidr);
+	} else {
+		thread_id = 0;
+		cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+		clus_id = MPIDR_AFFLVL1_VAL(mpidr);
+	}
+
+	if (clus_id >= FVP_CLUSTER_COUNT)
+		return -1;
+	if (cpu_id >= FVP_MAX_CPUS_PER_CLUSTER)
+		return -1;
+	if (thread_id >= FVP_MAX_PE_PER_CPU)
+		return -1;
+
 	if (fvp_pwrc_read_psysr(mpidr) == PSYSR_INVALID)
 		return -1;
 
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 7a7cf9e..bf038e9 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -68,10 +68,17 @@
 #define PLAT_ARM_TSP_UART_BASE		V2M_IOFPGA_UART2_BASE
 #define PLAT_ARM_TSP_UART_CLK_IN_HZ	V2M_IOFPGA_UART2_CLK_IN_HZ
 
+#define PLAT_FVP_SMMUV3_BASE		0x2b400000
+
 /* CCI related constants */
-#define PLAT_ARM_CCI_BASE		0x2c090000
-#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX	3
-#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX	4
+#define PLAT_FVP_CCI400_BASE		0x2c090000
+#define PLAT_FVP_CCI400_CLUS0_SL_PORT	3
+#define PLAT_FVP_CCI400_CLUS1_SL_PORT	4
+
+/* CCI-500/CCI-550 on Base platform */
+#define PLAT_FVP_CCI5XX_BASE		0x2a000000
+#define PLAT_FVP_CCI5XX_CLUS0_SL_PORT	5
+#define PLAT_FVP_CCI5XX_CLUS1_SL_PORT	6
 
 /* CCN related constants. Only CCN 502 is currently supported */
 #define PLAT_ARM_CCN_BASE		0x2e000000
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index d9c624c..0b6e1da 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -72,8 +72,7 @@
 endif
 
 ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCI)
-FVP_INTERCONNECT_SOURCES	:= 	drivers/arm/cci/cci.c		\
-					plat/arm/common/arm_cci.c
+FVP_INTERCONNECT_SOURCES	:= 	drivers/arm/cci/cci.c
 else ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCN)
 FVP_INTERCONNECT_SOURCES	:= 	drivers/arm/ccn/ccn.c		\
 					plat/arm/common/arm_ccn.c
@@ -136,7 +135,8 @@
 BL2U_SOURCES		+=	plat/arm/board/fvp/fvp_bl2u_setup.c		\
 				${FVP_SECURITY_SOURCES}
 
-BL31_SOURCES		+=	plat/arm/board/fvp/fvp_bl31_setup.c		\
+BL31_SOURCES		+=	drivers/arm/smmu/smmu_v3.c			\
+				plat/arm/board/fvp/fvp_bl31_setup.c		\
 				plat/arm/board/fvp/fvp_pm.c			\
 				plat/arm/board/fvp/fvp_topology.c		\
 				plat/arm/board/fvp/aarch64/fvp_helpers.S	\