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>
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 0000000..8d552ca
--- /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)
+		;
+}
+