summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSoby Mathew <soby.mathew@arm.com>2015-11-06 10:09:16 +0000
committerSoby Mathew <soby.mathew@arm.com>2016-02-04 16:59:19 +0000
commitaf059017bbba5cf5626c9dbfe8391e086158ca8e (patch)
tree228b37c6b95f1d9ac49bedd136dd1dc5a7934c2f /drivers
parentb122cb138c83402a1a5f1b9b04c41bf48ff7cae9 (diff)
Introduce GIC context save and restore functionality
This patch defines a set of APIs that help to save and restore the GIC state during suspend use cases. Earlier, the GIC was reinitialized by suspend framework and then the appropriate SGI state was restored by the SGI framework. Now the save and restore infrastructure is within the GIC driver and the framework invokes the appropriate save/restore functions of the ARM GIC layer. Change-Id: I7086316b50db09665886d2b31d1bec641568b6b5
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/arm_gic_v2.c21
-rw-r--r--drivers/arm/gic/gic_v2.c77
2 files changed, 98 insertions, 0 deletions
diff --git a/drivers/arm/gic/arm_gic_v2.c b/drivers/arm/gic/arm_gic_v2.c
index cbecb1c..122fe5a 100644
--- a/drivers/arm/gic/arm_gic_v2.c
+++ b/drivers/arm/gic/arm_gic_v2.c
@@ -50,6 +50,27 @@ void arm_gic_disable_interrupts_local(void)
gicv2_disable_cpuif();
}
+void arm_gic_save_context_local(void)
+{
+ gicv2_save_cpuif_context();
+}
+
+void arm_gic_restore_context_local(void)
+{
+ gicv2_restore_cpuif_context();
+}
+
+void arm_gic_save_context_global(void)
+{
+ gicv2_save_sgi_ppi_context();
+}
+
+void arm_gic_restore_context_global(void)
+{
+ gicv2_setup_distif();
+ gicv2_restore_sgi_ppi_context();
+}
+
void arm_gic_setup_global(void)
{
gicv2_setup_distif();
diff --git a/drivers/arm/gic/gic_v2.c b/drivers/arm/gic/gic_v2.c
index 4613767..b5c27fc 100644
--- a/drivers/arm/gic/gic_v2.c
+++ b/drivers/arm/gic/gic_v2.c
@@ -37,6 +37,22 @@
#include <mmio.h>
#include <platform.h>
+/*
+ * Data structure to store the GIC per CPU context before entering
+ * system suspend. Only the GIC context of first 32 interrupts (SGIs and PPIs)
+ * will be saved. The GIC SPI context needs to be restored by the respective
+ * drivers. The GICC_PMR is not saved here as it will be reinitialized during
+ * GIC restore.
+ */
+struct gicv2_pcpu_ctx {
+ unsigned int gicc_ctlr;
+ unsigned int gicd_isenabler0;
+ unsigned int gicd_ipriorityr[NUM_PCPU_INTR >> IPRIORITYR_SHIFT];
+ unsigned int gicd_icfgr;
+};
+
+static struct gicv2_pcpu_ctx pcpu_gic_ctx[PLATFORM_CORE_COUNT];
+
static uintptr_t gicc_base_addr;
static uintptr_t gicd_base_addr;
@@ -155,6 +171,28 @@ void gicv2_disable_cpuif(void)
gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
}
+void gicv2_save_cpuif_context(void)
+{
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicc_base_addr);
+ pcpu_gic_ctx[core_pos].gicc_ctlr =
+ gicc_read_ctlr(gicc_base_addr);
+}
+
+void gicv2_restore_cpuif_context(void)
+{
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicc_base_addr);
+
+ /* The GICC_PMR is never modified, hence we initialize this register */
+ gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
+
+ gicc_write_ctlr(gicc_base_addr,
+ pcpu_gic_ctx[core_pos].gicc_ctlr);
+}
+
void gicv2_setup_distif(void)
{
unsigned int gicd_ctlr;
@@ -167,6 +205,45 @@ void gicv2_setup_distif(void)
gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
}
+/* Save the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
+void gicv2_save_sgi_ppi_context(void)
+{
+ unsigned int i;
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicd_base_addr);
+ pcpu_gic_ctx[core_pos].gicd_isenabler0 =
+ gicd_read_isenabler(gicd_base_addr, 0);
+
+ /* Read the ipriority registers, 4 at a time */
+ for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
+ pcpu_gic_ctx[core_pos].gicd_ipriorityr[i] =
+ gicd_read_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT);
+
+ pcpu_gic_ctx[core_pos].gicd_icfgr =
+ gicd_read_icfgr(gicd_base_addr, MIN_PPI_ID);
+}
+
+/* Restore the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
+void gicv2_restore_sgi_ppi_context(void)
+{
+ unsigned int i;
+ unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
+
+ assert(gicd_base_addr);
+
+ /* Write the ipriority registers, 4 at a time */
+ for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
+ gicd_write_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT,
+ pcpu_gic_ctx[core_pos].gicd_ipriorityr[i]);
+
+ gicd_write_icfgr(gicd_base_addr, MIN_PPI_ID,
+ pcpu_gic_ctx[core_pos].gicd_icfgr);
+
+ gicd_write_isenabler(gicd_base_addr, 0,
+ pcpu_gic_ctx[core_pos].gicd_isenabler0);
+}
+
void gicv2_gicd_set_ipriorityr(unsigned int interrupt_id,
unsigned int priority)
{