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/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))