summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSoby Mathew <soby.mathew@arm.com>2017-07-13 15:19:51 +0100
committerSoby Mathew <soby.mathew@arm.com>2017-10-05 16:47:53 +0100
commitebf1ca10e466f39c45fa4ae4043fd53487d32362 (patch)
treed005dc71d6d0a9d5f64eb58d60fb355163942412 /drivers
parenta64b4e626ecad5d5a77dfd26c94a32c425748f4c (diff)
GICv3: add functions for save and restore
During system suspend, the GICv3 Distributor and Redistributor context can be lost due to power gating of the system power domain. This means that the GICv3 context needs to be saved prior to system suspend and restored on wakeup. Currently the consensus is that the Firmware should be in charge of this. See tf-issues#464 for more details. This patch introduces helper APIs in the GICv3 driver to save and restore the Distributor and Redistributor contexts. The GICv3 ITS context is not considered in this patch because the specification says that the details of ITS power management is implementation-defined. These APIs are expected to be appropriately invoked by the platform layer during system suspend. Fixes ARM-software/tf-issues#464 Change-Id: Iebb9c6770ab8c4d522546f161fa402d2fe02ec00 Signed-off-by: Soby Mathew <soby.mathew@arm.com> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/v3/arm_gicv3_common.c105
-rw-r--r--drivers/arm/gic/v3/gic500.c22
-rw-r--r--drivers/arm/gic/v3/gic600.c13
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c295
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h81
5 files changed, 513 insertions, 3 deletions
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
new file mode 100644
index 00000000..8d552ca5
--- /dev/null
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for implementation defined features that are identical in ARM GICv3
+* implementations (GIC-500 and GIC-600 for now). This driver only overrides
+* APIs that are different to those generic ones in GICv3 driver.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <gicv3.h>
+
+#include "gicv3_private.h"
+#include "arm_gicv3_common.h"
+
+/*
+ * Flush the internal GIC cache of the LPIs pending tables to memory before
+ * saving the state of the Redistributor. This is required before powering off
+ * the GIC when the pending status must be preserved.
+ * `rdist_proc_num` is the processor number corresponding to the Redistributor of the
+ * current CPU.
+ */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
+{
+ uintptr_t gicr_base = 0;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ /*
+ * The GICR_WAKER.Sleep bit should be set only when both
+ * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
+ * all the Redistributors.
+ */
+ for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) {
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[i];
+ assert(gicr_base);
+ assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
+ assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT);
+ }
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+ /*
+ * According to the TRM, there is only one instance of the
+ * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+ * through any of the Redistributor.
+ */
+
+ /*
+ * Set GICR_WAKER.Sleep
+ * After this point, the system must be configured so that the
+ * wake_request signals for the right cores are asserted when a wakeup
+ * interrupt is detected. The GIC will not be able to do that anymore
+ * when the GICR_WAKER.Sleep bit is set to 1.
+ */
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
+
+ /* Wait until the GICR_WAKER.Quiescent bit is set */
+ while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
+ ;
+}
+
+/*
+ * Allow the LPIs pending state to be read back from the tables in memory after
+ * having restored the state of the GIC Redistributor.
+ */
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
+{
+ uintptr_t gicr_base;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+
+ /*
+ * According to the TRM, there is only one instance of the
+ * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+ * through any of the Redistributor.
+ */
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+ assert(gicr_base);
+
+ /*
+ * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent
+ * bit is not set. We should be alright on power on path, therefore
+ * coming out of sleep and Quiescent should be set, but we assert in
+ * case.
+ */
+ assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT);
+
+ /* Clear GICR_WAKER.Sleep */
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT);
+
+ /*
+ * We don't know if the effects of setting GICR_WAKER.Sleep bit is
+ * instantaneous, so we wait until the interface is not Quiescent
+ * anymore.
+ */
+ while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT)
+ ;
+}
+
diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c
new file mode 100644
index 00000000..f03e33f8
--- /dev/null
+++ b/drivers/arm/gic/v3/gic500.c
@@ -0,0 +1,22 @@
+/*
+ * 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/gic600.c b/drivers/arm/gic/v3/gic600.c
index 217c08fd..eb4fc548 100644
--- a/drivers/arm/gic/v3/gic600.c
+++ b/drivers/arm/gic/v3/gic600.c
@@ -32,9 +32,6 @@
#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)
{
@@ -82,6 +79,16 @@ static void gic600_pwr_off(uintptr_t base)
}
}
+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);
+}
+
/*
* Power off GIC600 redistributor
*/
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index b68d9988..83bf430f 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -21,6 +21,27 @@ static unsigned int gicv2_compat;
#pragma weak gicv3_rdistif_off
#pragma weak gicv3_rdistif_on
+
+/* Helper macros to save and restore GICD registers to and from the context */
+#define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_SPI_ID; int_id < intr_num; \
+ int_id += (1 << REG##_SHIFT)) { \
+ gicd_write_##reg(base, int_id, \
+ ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \
+ } \
+ } while (0)
+
+#define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_SPI_ID; int_id < intr_num; \
+ int_id += (1 << REG##_SHIFT)) { \
+ ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\
+ gicd_read_##reg(base, int_id); \
+ } \
+ } while (0)
+
+
/*******************************************************************************
* This function initialises the ARM GICv3 driver in EL3 with provided platform
* inputs.
@@ -406,3 +427,277 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
/* Else it is a Group 0 Secure interrupt */
return INTR_GROUP0;
}
+
+/*****************************************************************************
+ * Function to save the GIC Redistributor register context. This function
+ * must be invoked after CPU interface disable and prior to Distributor save.
+ *****************************************************************************/
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx)
+{
+ uintptr_t gicr_base;
+ unsigned int int_id;
+
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(IS_IN_EL3());
+ assert(rdist_ctx);
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ /*
+ * Wait for any write to GICR_CTLR to complete before trying to save any
+ * state.
+ */
+ gicr_wait_for_pending_write(gicr_base);
+
+ rdist_ctx->gicr_ctlr = gicr_read_ctlr(gicr_base);
+
+ rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base);
+ rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base);
+
+ rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base);
+ rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base);
+ rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base);
+ rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base);
+ rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base);
+ rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base);
+ rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base);
+ rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
+ for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+ int_id += (1 << IPRIORITYR_SHIFT)) {
+ rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] =
+ gicr_read_ipriorityr(gicr_base, int_id);
+ }
+
+
+ /*
+ * Call the pre-save hook that implements the IMP DEF sequence that may
+ * be required on some GIC implementations. As this may need to access
+ * the Redistributor registers, we pass it proc_num.
+ */
+ gicv3_distif_pre_save(proc_num);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Redistributor register context. We disable
+ * LPI and per-cpu interrupts before we start restore of the Redistributor.
+ * This function must be invoked after Distributor restore but prior to
+ * CPU interface enable. The pending and active interrupts are restored
+ * after the interrupts are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_rdistif_init_restore(unsigned int proc_num,
+ const gicv3_redist_ctx_t * const rdist_ctx)
+{
+ uintptr_t gicr_base;
+ unsigned int int_id;
+
+ assert(gicv3_driver_data);
+ assert(proc_num < gicv3_driver_data->rdistif_num);
+ assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(IS_IN_EL3());
+ assert(rdist_ctx);
+
+ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+ /* Power on redistributor */
+ gicv3_rdistif_on(proc_num);
+
+ /*
+ * Call the post-restore hook that implements the IMP DEF sequence that
+ * may be required on some GIC implementations. As this may need to
+ * access the Redistributor registers, we pass it proc_num.
+ */
+ gicv3_distif_post_restore(proc_num);
+
+ /*
+ * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+ * more scalable approach as it avoids clearing the enable bits in the
+ * GICD_CTLR
+ */
+ gicr_write_icenabler0(gicr_base, ~0);
+ /* Wait for pending writes to GICR_ICENABLER */
+ gicr_wait_for_pending_write(gicr_base);
+
+ /*
+ * Disable the LPIs to avoid unpredictable behavior when writing to
+ * GICR_PROPBASER and GICR_PENDBASER.
+ */
+ gicr_write_ctlr(gicr_base,
+ rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT));
+
+ /* Restore registers' content */
+ gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
+ gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
+
+ gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0);
+
+ for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+ int_id += (1 << IPRIORITYR_SHIFT)) {
+ gicr_write_ipriorityr(gicr_base, int_id,
+ rdist_ctx->gicr_ipriorityr[
+ (int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]);
+ }
+
+ gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0);
+ gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1);
+ gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0);
+ gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr);
+
+ /* Restore after group and priorities are set */
+ gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0);
+ gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0);
+
+ /*
+ * Wait for all writes to the Distributor to complete before enabling
+ * the SGI and PPIs.
+ */
+ gicr_wait_for_upstream_pending_write(gicr_base);
+ gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0);
+
+ /*
+ * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case
+ * the first write to GICR_CTLR was still in flight (this write only
+ * restores GICR_CTLR.Enable_LPIs and no waiting is required for this
+ * bit).
+ */
+ gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr);
+ gicr_wait_for_pending_write(gicr_base);
+}
+
+/*****************************************************************************
+ * Function to save the GIC Distributor register context. This function
+ * must be invoked after CPU interface disable and Redistributor save.
+ *****************************************************************************/
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
+{
+ unsigned int num_ints;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(IS_IN_EL3());
+ assert(dist_ctx);
+
+ uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+ num_ints = gicd_read_typer(gicd_base);
+ num_ints &= TYPER_IT_LINES_NO_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ assert(num_ints <= MAX_SPI_ID + 1);
+
+ /* Wait for pending write to complete */
+ gicd_wait_for_pending_write(gicd_base);
+
+ /* Save the GICD_CTLR */
+ dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
+
+ /* Save GICD_IGROUPR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+ /* Save GICD_ISENABLER for INT_IDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+ /* Save GICD_ISPENDR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+ /* Save GICD_ISACTIVER for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+ /* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+ /* Save GICD_ICFGR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+ /* Save GICD_IGRPMODR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+ /* Save GICD_NSACR for INTIDs 32 - 1020 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+ /* Save GICD_IROUTER for INTIDs 32 - 1024 */
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+ /*
+ * GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> are RAZ/WI when
+ * GICD_CTLR.ARE_(S|NS) bits are set which is the case for our GICv3
+ * driver.
+ */
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Distributor register context. We disable G0, G1S
+ * and G1NS interrupt groups before we start restore of the Distributor. This
+ * function must be invoked prior to Redistributor restore and CPU interface
+ * enable. The pending and active interrupts are restored after the interrupts
+ * are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
+{
+ unsigned int num_ints = 0;
+
+ assert(gicv3_driver_data);
+ assert(gicv3_driver_data->gicd_base);
+ assert(IS_IN_EL3());
+ assert(dist_ctx);
+
+ uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+ /*
+ * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
+ * the ARE_S bit. The Distributor might generate a system error
+ * otherwise.
+ */
+ gicd_clr_ctlr(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(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
+
+ num_ints = gicd_read_typer(gicd_base);
+ num_ints &= TYPER_IT_LINES_NO_MASK;
+ num_ints = (num_ints + 1) << 5;
+
+ assert(num_ints <= MAX_SPI_ID + 1);
+
+ /* Restore GICD_IGROUPR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+ /* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+ /* Restore GICD_ICFGR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+ /* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+ /* Restore GICD_NSACR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+ /* Restore GICD_IROUTER for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+ /*
+ * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are
+ * configured.
+ */
+
+ /* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+ /* Restore GICD_ISPENDR for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+ /* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+ /* Restore the GICD_CTLR */
+ gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr);
+ gicd_wait_for_pending_write(gicd_base);
+
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index da4bcbf7..7224e067 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -7,6 +7,7 @@
#ifndef __GICV3_PRIVATE_H__
#define __GICV3_PRIVATE_H__
+#include <assert.h>
#include <gic_common.h>
#include <gicv3.h>
#include <mmio.h>
@@ -43,6 +44,11 @@
#endif
/*******************************************************************************
+ * GICv3 private global variables declarations
+ ******************************************************************************/
+extern const gicv3_driver_data_t *gicv3_driver_data;
+
+/*******************************************************************************
* Private GICv3 function prototypes for accessing entire registers.
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
@@ -150,6 +156,11 @@ static inline unsigned long long gicr_read_ctlr(uintptr_t base)
return mmio_read_64(base + GICR_CTLR);
}
+static inline void gicr_write_ctlr(uintptr_t base, uint64_t val)
+{
+ mmio_write_64(base + GICR_CTLR, val);
+}
+
static inline unsigned long long gicr_read_typer(uintptr_t base)
{
return mmio_read_64(base + GICR_TYPER);
@@ -178,6 +189,16 @@ static inline void gicr_wait_for_pending_write(uintptr_t gicr_base)
;
}
+static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base)
+{
+ while (gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT)
+ ;
+}
+
+/* Private implementation of Distributor power control hooks */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num);
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num);
+
/*******************************************************************************
* GIC Re-distributor functions for accessing entire registers.
* Note: The raw register values correspond to multiple interrupt IDs and
@@ -208,6 +229,16 @@ static inline unsigned int gicr_read_igroupr0(uintptr_t base)
return mmio_read_32(base + GICR_IGROUPR0);
}
+static inline unsigned int gicr_read_ispendr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ISPENDR0);
+}
+
+static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISPENDR0, val);
+}
+
static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICR_IGROUPR0, val);
@@ -223,14 +254,64 @@ static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val)
mmio_write_32(base + GICR_IGRPMODR0, val);
}
+static inline unsigned int gicr_read_nsacr(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_NSACR);
+}
+
+static inline void gicr_write_nsacr(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_NSACR, val);
+}
+
+static inline unsigned int gicr_read_isactiver0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ISACTIVER0);
+}
+
+static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ISACTIVER0, val);
+}
+
+static inline unsigned int gicr_read_icfgr0(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_ICFGR0);
+}
+
static inline unsigned int gicr_read_icfgr1(uintptr_t base)
{
return mmio_read_32(base + GICR_ICFGR1);
}
+static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_ICFGR0, val);
+}
+
static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
{
mmio_write_32(base + GICR_ICFGR1, val);
}
+static inline unsigned int gicr_read_propbaser(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_PROPBASER);
+}
+
+static inline void gicr_write_propbaser(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_PROPBASER, val);
+}
+
+static inline unsigned int gicr_read_pendbaser(uintptr_t base)
+{
+ return mmio_read_32(base + GICR_PENDBASER);
+}
+
+static inline void gicr_write_pendbaser(uintptr_t base, unsigned int val)
+{
+ mmio_write_32(base + GICR_PENDBASER, val);
+}
+
#endif /* __GICV3_PRIVATE_H__ */