aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/user-guide.md1
-rw-r--r--drivers/arm/gic/v3/gic600.c119
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c104
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h4
-rw-r--r--plat/arm/board/fvp/platform.mk11
5 files changed, 183 insertions, 56 deletions
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 5165000d3..21e1f9991 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -641,6 +641,7 @@ map is explained in the [Firmware Design].
if `FVP_CLUSTER_COUNT` > 2.
* `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)
- `FVP_GICV3_LEGACY`: The Legacy GICv3 driver is selected (deprecated)
diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic600.c
new file mode 100644
index 000000000..4ea31ab16
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC600-specific features. This driver only overrides APIs that are
+ * different to those generic ones in GICv3 driver.
+ *
+ * GIC600 supports independently power-gating redistributor interface.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <gicv3.h>
+
+#include "gicv3_private.h"
+
+/* GIC600-specific register offsets */
+#define GICR_PWRR 0x24
+
+/* GICR_PWRR fields */
+#define PWRR_RDPD_SHIFT 0
+#define PWRR_RDGPD_SHIFT 2
+#define PWRR_RDGPO_SHIFT 3
+
+#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT)
+#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT)
+
+/* Values to write to GICR_PWRR register to power redistributor */
+#define PWRR_ON (0 << PWRR_RDPD_SHIFT)
+#define PWRR_OFF (1 << PWRR_RDPD_SHIFT)
+
+/* Generic GICv3 resources */
+extern const gicv3_driver_data_t *gicv3_driver_data;
+
+/* GIC600-specific accessor functions */
+static void gicr_write_pwrr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_PWRR, val);
+}
+
+static uint32_t gicr_read_pwrr(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_PWRR);
+}
+
+static int gicr_group_powering_down(uint32_t pwrr)
+{
+ /*
+ * Whether the redistributor group power down operation is in transit:
+ * i.e. it's intending to, but not finished yet.
+ */
+ return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO));
+}
+
+static void gic600_pwr_on(uintptr_t base)
+{
+ /* Power on redistributor */
+ gicr_write_pwrr(base, PWRR_ON);
+
+ /* Wait until the power on state is reflected */
+ while (gicr_read_pwrr(base) & PWRR_RDGPO)
+ ;
+}
+
+static void gic600_pwr_off(uintptr_t base)
+{
+ /* Power off redistributor */
+ gicr_write_pwrr(base, PWRR_OFF);
+
+ /*
+ * If this is the last man, turning this redistributor frame off will
+ * result in the group itself being powered off. In that case, wait as
+ * long as it's in transition, or has aborted the transition altogether
+ * for any reason.
+ */
+ if (gicr_read_pwrr(base) & PWRR_RDGPD) {
+ while (gicr_group_powering_down(gicr_read_pwrr(base)))
+ ;
+ }
+}
+
+/*
+ * Power off GIC600 redistributor
+ */
+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);
+
+ /* Attempt to power redistributor off */
+ gic600_pwr_off(gicr_base);
+}
+
+/*
+ * Power on GIC600 redistributor
+ */
+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);
+
+ /* Power redistributor on */
+ gic600_pwr_on(gicr_base);
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 566c446d6..b68d99882 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -8,12 +8,10 @@
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
-#include <gic_common.h>
#include <gicv3.h>
-#include "../common/gic_common_private.h"
#include "gicv3_private.h"
-static const gicv3_driver_data_t *driver_data;
+const gicv3_driver_data_t *gicv3_driver_data;
static unsigned int gicv2_compat;
/*
@@ -90,18 +88,20 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
plat_driver_data->gicr_base,
plat_driver_data->mpidr_to_core_pos);
- driver_data = plat_driver_data;
+ gicv3_driver_data = plat_driver_data;
/*
* The GIC driver data is initialized by the primary CPU with caches
* enabled. When the secondary CPU boots up, it initializes the
* GICC/GICR interface with the caches disabled. Hence flush the
- * driver_data to ensure coherency. This is not required if the
+ * driver data to ensure coherency. This is not required if the
* platform has HW_ASSISTED_COHERENCY enabled.
*/
#if !HW_ASSISTED_COHERENCY
- flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data));
- flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data));
+ flush_dcache_range((uintptr_t) &gicv3_driver_data,
+ sizeof(gicv3_driver_data));
+ flush_dcache_range((uintptr_t) gicv3_driver_data,
+ sizeof(*gicv3_driver_data));
#endif
INFO("GICv3 %s legacy support detected."
@@ -117,10 +117,10 @@ void gicv3_distif_init(void)
{
unsigned int bitmap = 0;
- assert(driver_data);
- assert(driver_data->gicd_base);
- assert(driver_data->g1s_interrupt_array ||
- driver_data->g0_interrupt_array);
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(gicv3_driver_data->g1s_interrupt_array ||
+ gicv3_driver_data->g0_interrupt_array);
assert(IS_IN_EL3());
@@ -129,39 +129,39 @@ void gicv3_distif_init(void)
* the ARE_S bit. The Distributor might generate a system error
* otherwise.
*/
- gicd_clr_ctlr(driver_data->gicd_base,
+ gicd_clr_ctlr(gicv3_driver_data->gicd_base,
CTLR_ENABLE_G0_BIT |
CTLR_ENABLE_G1S_BIT |
CTLR_ENABLE_G1NS_BIT,
RWP_TRUE);
/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
- gicd_set_ctlr(driver_data->gicd_base,
+ gicd_set_ctlr(gicv3_driver_data->gicd_base,
CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
/* Set the default attribute of all SPIs */
- gicv3_spis_configure_defaults(driver_data->gicd_base);
+ gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base);
/* Configure the G1S SPIs */
- if (driver_data->g1s_interrupt_array) {
- gicv3_secure_spis_configure(driver_data->gicd_base,
- driver_data->g1s_interrupt_num,
- driver_data->g1s_interrupt_array,
+ if (gicv3_driver_data->g1s_interrupt_array) {
+ gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+ gicv3_driver_data->g1s_interrupt_num,
+ gicv3_driver_data->g1s_interrupt_array,
INTR_GROUP1S);
bitmap |= CTLR_ENABLE_G1S_BIT;
}
/* Configure the G0 SPIs */
- if (driver_data->g0_interrupt_array) {
- gicv3_secure_spis_configure(driver_data->gicd_base,
- driver_data->g0_interrupt_num,
- driver_data->g0_interrupt_array,
+ if (gicv3_driver_data->g0_interrupt_array) {
+ gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+ gicv3_driver_data->g0_interrupt_num,
+ gicv3_driver_data->g0_interrupt_array,
INTR_GROUP0);
bitmap |= CTLR_ENABLE_G0_BIT;
}
/* Enable the secure SPIs now that they have been configured */
- gicd_set_ctlr(driver_data->gicd_base, bitmap, RWP_TRUE);
+ gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
}
/*******************************************************************************
@@ -173,37 +173,37 @@ void gicv3_rdistif_init(unsigned int proc_num)
{
uintptr_t gicr_base;
- assert(driver_data);
- assert(proc_num < driver_data->rdistif_num);
- assert(driver_data->rdistif_base_addrs);
- assert(driver_data->gicd_base);
- assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT);
- assert(driver_data->g1s_interrupt_array ||
- driver_data->g0_interrupt_array);
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(gicv3_driver_data->gicd_base);
+ assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT);
+ assert(gicv3_driver_data->g1s_interrupt_array ||
+ gicv3_driver_data->g0_interrupt_array);
assert(IS_IN_EL3());
/* Power on redistributor */
gicv3_rdistif_on(proc_num);
- gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
/* Set the default attribute of all SGIs and PPIs */
gicv3_ppi_sgi_configure_defaults(gicr_base);
/* Configure the G1S SGIs/PPIs */
- if (driver_data->g1s_interrupt_array) {
+ if (gicv3_driver_data->g1s_interrupt_array) {
gicv3_secure_ppi_sgi_configure(gicr_base,
- driver_data->g1s_interrupt_num,
- driver_data->g1s_interrupt_array,
+ gicv3_driver_data->g1s_interrupt_num,
+ gicv3_driver_data->g1s_interrupt_array,
INTR_GROUP1S);
}
/* Configure the G0 SGIs/PPIs */
- if (driver_data->g0_interrupt_array) {
+ if (gicv3_driver_data->g0_interrupt_array) {
gicv3_secure_ppi_sgi_configure(gicr_base,
- driver_data->g0_interrupt_num,
- driver_data->g0_interrupt_array,
+ gicv3_driver_data->g0_interrupt_num,
+ gicv3_driver_data->g0_interrupt_array,
INTR_GROUP0);
}
}
@@ -231,13 +231,13 @@ void gicv3_cpuif_enable(unsigned int proc_num)
unsigned int scr_el3;
unsigned int icc_sre_el3;
- assert(driver_data);
- assert(proc_num < driver_data->rdistif_num);
- assert(driver_data->rdistif_base_addrs);
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
assert(IS_IN_EL3());
/* Mark the connected core as awake */
- gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
gicv3_rdistif_mark_core_awake(gicr_base);
/* Disable the legacy interrupt bypass */
@@ -291,9 +291,9 @@ void gicv3_cpuif_disable(unsigned int proc_num)
{
uintptr_t gicr_base;
- assert(driver_data);
- assert(proc_num < driver_data->rdistif_num);
- assert(driver_data->rdistif_base_addrs);
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
assert(IS_IN_EL3());
@@ -314,7 +314,7 @@ void gicv3_cpuif_disable(unsigned int proc_num)
isb();
/* Mark the connected core as asleep */
- gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
gicv3_rdistif_mark_core_asleep(gicr_base);
}
@@ -371,25 +371,25 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
uintptr_t gicr_base;
assert(IS_IN_EL3());
- assert(driver_data);
+ assert(gicv3_driver_data);
/* Ensure the parameters are valid */
assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID);
- assert(proc_num < driver_data->rdistif_num);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
/* All LPI interrupts are Group 1 non secure */
if (id >= MIN_LPI_ID)
return INTR_GROUP1NS;
if (id < MIN_SPI_ID) {
- assert(driver_data->rdistif_base_addrs);
- gicr_base = driver_data->rdistif_base_addrs[proc_num];
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
igroup = gicr_get_igroupr0(gicr_base, id);
grpmodr = gicr_get_igrpmodr0(gicr_base, id);
} else {
- assert(driver_data->gicd_base);
- igroup = gicd_get_igroupr(driver_data->gicd_base, id);
- grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id);
+ assert(gicv3_driver_data->gicd_base);
+ igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
+ grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
}
/*
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index 473fdb15b..f95cfab65 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,9 +7,11 @@
#ifndef __GICV3_PRIVATE_H__
#define __GICV3_PRIVATE_H__
+#include <gic_common.h>
#include <gicv3.h>
#include <mmio.h>
#include <stdint.h>
+#include "../common/gic_common_private.h"
/*******************************************************************************
* GICv3 private macro definitions
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 6a759c5a7..0baa8267e 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -31,13 +31,18 @@ endif
$(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}, FVP_GICV3)
-FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
+FVP_GICV3_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \
plat/common/plat_gicv3.c \
plat/arm/common/arm_gicv3.c
+
+# Choose the GIC sources depending upon the how the FVP will be invoked
+ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
+FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES}
+else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600)
+FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \
+ drivers/arm/gic/v3/gic600.c
else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_main.c \