--- /dev/null
+/*
+ * 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);
+}
#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;
/*
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."
{
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());
* 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);
}
/*******************************************************************************
{
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);
}
}
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 */
{
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());
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);
}
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);
}
/*