summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2019-11-22 14:04:55 +0800
committerAnson Huang <Anson.Huang@nxp.com>2019-12-13 10:41:30 +0800
commitd3150a3f33c225b852be8bd7e7b143616234d69b (patch)
tree1f2ebf3646073b586eb7977af729b47394ca2d6e /drivers
parent81624751253d867ba9a3e5a8a0f4580b7b8cdb54 (diff)
gic: make sure ProcessorSleep bit clear successfully
GICR_WAKER.ProcessorSleep can only be set to zero when: — GICR_WAKER.Sleep bit[0] == 0. — GICR_WAKER.Quiescent bit[31] == 0. On some platforms, when system reboot with GIC in sleep mode but with power ON, such as on NXP's i.MX8QM, Linux kernel enters suspend but could be requested to reboot, and GIC is in sleep mode and it is inside a power domain which is ON in this scenario, when CPU reset, the GIC driver trys to set CORE's redistributor interface to awake, with GICR_WAKER.Sleep bit[0] and GICR_WAKER.Quiescent bit[31] both set, the ProcessorSleep bit[1] will never be clear and cause system hang. This patch makes sure GICR_WAKER.Sleep bit[0] and GICR_WAKER.Quiescent bit[31] are both zeor before clearing ProcessorSleep bit[1]. Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/v3/gicv3_helpers.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
index 710532e3..d599596c 100644
--- a/drivers/arm/gic/v3/gicv3_helpers.c
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -10,6 +10,7 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <common/interrupt_props.h>
+#include <drivers/arm/arm_gicv3_common.h>
#include <drivers/arm/gic_common.h>
#include "../common/gic_common_private.h"
@@ -284,6 +285,19 @@ void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base)
*/
assert((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U);
+ /*
+ * ProcessorSleep bit can ONLY be set to zero when
+ * Quiescent bit and Sleep bit are both zero, so
+ * need to make sure Quiescent bit and Sleep bit
+ * are zero before clearing ProcessorSleep bit.
+ */
+ if (gicr_read_waker(gicr_base) & WAKER_QSC_BIT) {
+ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT);
+ /* Wait till the WAKER_QSC_BIT changes to 0 */
+ while ((gicr_read_waker(gicr_base) & WAKER_QSC_BIT) != 0U)
+ ;
+ }
+
/* Mark the connected core as awake */
gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT);