GICv3: GIC-600: Detect GIC-600 at runtime

The only difference between GIC-500 and GIC-600 relevant to TF-A is the
differing power management sequence.
A certain GIC implementation is detectable at runtime, for instance by
checking the IIDR register. Let's add that test before initiating the
GIC-600 specific sequence, so the code can be used on both GIC-600 and
GIC-500 chips alike, without deciding on a GIC chip at compile time.

This means that the GIC-500 "driver" is now redundant. To allow minimal
platform support, add a switch to disable GIC-600 support.

Change-Id: I17ea97d9fb05874772ebaa13e6678b4ba3415557
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index c863079..19b5653 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -711,8 +711,10 @@
 The driver can be configured with the following options set in the platform
 makefile:
 
--  ``GICV3_IMPL``: Selects between GIC-500 and GIC-600 variants of GICv3.
-   This option can take values GIC500 and GIC600 with default set to GIC500.
+-  ``GICV3_SUPPORT_GIC600``: Add support for the GIC-600 variants of GICv3.
+   Enabling this option will add runtime detection support for the
+   GIC-600, so is safe to select even for a GIC500 implementation.
+   This option defaults to 0.
 
 -  ``GICV3_IMPL_GIC600_MULTICHIP``: Selects GIC-600 variant with multichip
    functionality. This option defaults to 0
diff --git a/docs/plat/arm/fvp/index.rst b/docs/plat/arm/fvp/index.rst
index eb7eb00..f23ec28 100644
--- a/docs/plat/arm/fvp/index.rst
+++ b/docs/plat/arm/fvp/index.rst
@@ -116,7 +116,6 @@
 
 -  ``FVP_USE_GIC_DRIVER`` : Selects the GIC driver to be built. Options:
 
-   -  ``FVP_GIC600`` : The GIC600 implementation of GICv3 is selected
    -  ``FVP_GICV2`` : The GICv2 only driver is selected
    -  ``FVP_GICV3`` : The GICv3 only driver is selected (default option)
 
diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic-x00.c
similarity index 76%
rename from drivers/arm/gic/v3/gic600.c
rename to drivers/arm/gic/v3/gic-x00.c
index 59652da..c1a9f0d 100644
--- a/drivers/arm/gic/v3/gic600.c
+++ b/drivers/arm/gic/v3/gic-x00.c
@@ -5,8 +5,9 @@
  */
 
 /*
- * Driver for GIC-600 specific features. This driver only overrides
- * APIs that are different to those generic ones in GICv3 driver.
+ * Driver for GIC-500 and GIC-600 specific features. This driver only
+ * overrides APIs that are different to those generic ones in GICv3
+ * driver.
  *
  * GIC-600 supports independently power-gating redistributor interface.
  */
@@ -19,7 +20,8 @@
 #include "gicv3_private.h"
 
 /* GIC-600 specific register offsets */
-#define GICR_PWRR	0x24
+#define GICR_PWRR		0x24
+#define IIDR_MODEL_ARM_GIC_600	0x0200043b
 
 /* GICR_PWRR fields */
 #define PWRR_RDPD_SHIFT		0
@@ -39,6 +41,8 @@
 #define PWRR_ON		(0 << PWRR_RDPD_SHIFT)
 #define PWRR_OFF	(1 << PWRR_RDPD_SHIFT)
 
+#if GICV3_SUPPORT_GIC600
+
 /* GIC-600 specific accessor functions */
 static void gicr_write_pwrr(uintptr_t base, unsigned int val)
 {
@@ -93,6 +97,29 @@
 	}
 }
 
+static uintptr_t get_gicr_base(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base);
+
+	return gicr_base;
+}
+
+static bool gicv3_is_gic600(uintptr_t gicr_base)
+{
+	uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR);
+
+	return (reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600;
+}
+
+#endif
+
 void gicv3_distif_pre_save(unsigned int proc_num)
 {
 	arm_gicv3_distif_pre_save(proc_num);
@@ -103,38 +130,33 @@
 	arm_gicv3_distif_post_restore(proc_num);
 }
 
+
 /*
- * Power off GIC-600 redistributor
+ * Power off GIC-600 redistributor (if configured and detected)
  */
 void gicv3_rdistif_off(unsigned int proc_num)
 {
-	uintptr_t gicr_base;
-
-	assert(gicv3_driver_data);
-	assert(proc_num < gicv3_driver_data->rdistif_num);
-	assert(gicv3_driver_data->rdistif_base_addrs);
-
-	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
-	assert(gicr_base);
+#if GICV3_SUPPORT_GIC600
+	uintptr_t gicr_base = get_gicr_base(proc_num);
 
 	/* Attempt to power redistributor off */
-	gic600_pwr_off(gicr_base);
+	if (gicv3_is_gic600(gicr_base)) {
+		gic600_pwr_off(gicr_base);
+	}
+#endif
 }
 
 /*
- * Power on GIC-600 redistributor
+ * Power on GIC-600 redistributor (if configured and detected)
  */
 void gicv3_rdistif_on(unsigned int proc_num)
 {
-	uintptr_t gicr_base;
-
-	assert(gicv3_driver_data);
-	assert(proc_num < gicv3_driver_data->rdistif_num);
-	assert(gicv3_driver_data->rdistif_base_addrs);
-
-	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
-	assert(gicr_base);
+#if GICV3_SUPPORT_GIC600
+	uintptr_t gicr_base = get_gicr_base(proc_num);
 
 	/* Power redistributor on */
-	gic600_pwr_on(gicr_base);
+	if (gicv3_is_gic600(gicr_base)) {
+		gic600_pwr_on(gicr_base);
+	}
+#endif
 }
diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c
deleted file mode 100644
index f03e33f..0000000
--- a/drivers/arm/gic/v3/gic500.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-/*
- * Driver for GIC500-specific features. This driver only overrides APIs that are
- * different to those generic ones in GICv3 driver.
- */
-#include "gicv3_private.h"
-
-void gicv3_distif_pre_save(unsigned int proc_num)
-{
-	arm_gicv3_distif_pre_save(proc_num);
-}
-
-void gicv3_distif_post_restore(unsigned int proc_num)
-{
-	arm_gicv3_distif_post_restore(proc_num);
-}
-
diff --git a/drivers/arm/gic/v3/gicv3.mk b/drivers/arm/gic/v3/gicv3.mk
index 0f40103..a2fc16f 100644
--- a/drivers/arm/gic/v3/gicv3.mk
+++ b/drivers/arm/gic/v3/gicv3.mk
@@ -5,7 +5,7 @@
 #
 
 # Default configuration values
-GICV3_IMPL			?=	GIC500
+GICV3_SUPPORT_GIC600		?=	0
 GICV3_IMPL_GIC600_MULTICHIP	?=	0
 GICV3_OVERRIDE_DISTIF_PWR_OPS	?=	0
 GIC_ENABLE_V4_EXTN		?=	0
@@ -20,19 +20,14 @@
 GICV3_SOURCES	+=	drivers/arm/gic/v3/arm_gicv3_common.c
 endif
 
-# Either GIC-600 or GIC-500 can be selected at one time
-ifeq (${GICV3_IMPL}, GIC600)
-# GIC-600 sources
-GICV3_SOURCES	+=	drivers/arm/gic/v3/gic600.c
+GICV3_SOURCES	+=	drivers/arm/gic/v3/gic-x00.c
 ifeq (${GICV3_IMPL_GIC600_MULTICHIP}, 1)
 GICV3_SOURCES	+=	drivers/arm/gic/v3/gic600_multichip.c
 endif
-else ifeq (${GICV3_IMPL}, GIC500)
-# GIC-500 sources
-GICV3_SOURCES	+=	drivers/arm/gic/v3/gic500.c
-else
-$(error "Incorrect GICV3_IMPL value ${GICV3_IMPL}")
-endif
+
+# Set GIC-600 support
+$(eval $(call assert_boolean,GICV3_SUPPORT_GIC600))
+$(eval $(call add_define,GICV3_SUPPORT_GIC600))
 
 # Set GICv4 extension
 $(eval $(call assert_boolean,GIC_ENABLE_V4_EXTN))
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index 03596b9..77dc350 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -222,6 +222,14 @@
 #define TYPER_PPI_NUM_SHIFT	U(27)
 #define TYPER_PPI_NUM_MASK	U(0x1f)
 
+/* GICR_IIDR bit definitions */
+#define IIDR_PRODUCT_ID_MASK	0xff000000
+#define IIDR_VARIANT_MASK	0x000f0000
+#define IIDR_REVISION_MASK	0x0000f000
+#define IIDR_IMPLEMENTER_MASK	0x00000fff
+#define IIDR_MODEL_MASK		(IIDR_PRODUCT_ID_MASK | \
+				 IIDR_IMPLEMENTER_MASK)
+
 /*******************************************************************************
  * GICv3 and 3.1 CPU interface registers & constants
  ******************************************************************************/
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
index 7039a6d..34e50ea 100644
--- a/plat/arm/board/arm_fpga/platform.mk
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -70,8 +70,8 @@
 				lib/cpus/aarch64/cortex_a75.S
 endif
 
-# GIC-600 configuration
-GICV3_IMPL		:=	GIC600
+# Allow detection of GIC-600
+GICV3_SUPPORT_GIC600	:=	1
 
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 024e682..528948a 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -49,13 +49,10 @@
 $(eval $(call add_define,FVP_INTERCONNECT_DRIVER))
 
 # Choose the GIC sources depending upon the how the FVP will be invoked
-ifeq (${FVP_USE_GIC_DRIVER},$(filter ${FVP_USE_GIC_DRIVER},FVP_GICV3 FVP_GIC600))
-
-	# GIC500 is the default option in case GICV3_IMPL is not set
-	ifeq (${FVP_USE_GIC_DRIVER}, FVP_GIC600)
-		GICV3_IMPL	:=	GIC600
-	endif
+ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
 
+# The GIC model (GIC-600 or GIC-500) will be detected at runtime
+GICV3_SUPPORT_GIC600		:=	1
 GICV3_OVERRIDE_DISTIF_PWR_OPS	:=	1
 
 # Include GICv3 driver files
diff --git a/plat/arm/board/n1sdp/platform.mk b/plat/arm/board/n1sdp/platform.mk
index 44f7b8a..0bd3a21 100644
--- a/plat/arm/board/n1sdp/platform.mk
+++ b/plat/arm/board/n1sdp/platform.mk
@@ -15,7 +15,7 @@
 N1SDP_CPU_SOURCES	:=	lib/cpus/aarch64/neoverse_n1.S
 
 # GIC-600 configuration
-GICV3_IMPL			:=	GIC600
+GICV3_SUPPORT_GIC600		:=	1
 GICV3_IMPL_GIC600_MULTICHIP	:=	1
 
 # Include GICv3 driver files
diff --git a/plat/arm/board/tc0/platform.mk b/plat/arm/board/tc0/platform.mk
index 265826f..7f514cc 100644
--- a/plat/arm/board/tc0/platform.mk
+++ b/plat/arm/board/tc0/platform.mk
@@ -25,7 +25,8 @@
 GIC_ENABLE_V4_EXTN	:=      1
 
 # GIC-600 configuration
-GICV3_IMPL		:=	GIC600
+GICV3_SUPPORT_GIC600	:=	1
+
 
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk
diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/css/sgi/sgi-common.mk
index 2504581..6b9e0cd 100644
--- a/plat/arm/css/sgi/sgi-common.mk
+++ b/plat/arm/css/sgi/sgi-common.mk
@@ -23,7 +23,7 @@
 PLAT_INCLUDES		+=	-I${CSS_ENT_BASE}/include
 
 # GIC-600 configuration
-GICV3_IMPL			:=	GIC600
+GICV3_SUPPORT_GIC600	:=	1
 
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk
diff --git a/plat/arm/css/sgm/sgm-common.mk b/plat/arm/css/sgm/sgm-common.mk
index 60e9fb2..5b954f8 100644
--- a/plat/arm/css/sgm/sgm-common.mk
+++ b/plat/arm/css/sgm/sgm-common.mk
@@ -23,7 +23,7 @@
 INTERCONNECT_SOURCES	:=	${CSS_SGM_BASE}/sgm_interconnect.c
 
 # GIC-600 configuration
-GICV3_IMPL		:=	GIC600
+GICV3_SUPPORT_GIC600	:=	1
 
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk