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