From e655fefcea5e77323b19549ba39f914442e7bf5f Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 1 Mar 2019 10:51:38 +0800 Subject: [PATCH] imx: make sure GIC redistributor is awake before initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- plat/imx/common/plat_imx8_gic.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plat/imx/common/plat_imx8_gic.c b/plat/imx/common/plat_imx8_gic.c index 27c525b72..3a7dcfec6 100644 --- a/plat/imx/common/plat_imx8_gic.c +++ b/plat/imx/common/plat_imx8_gic.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -52,8 +54,27 @@ void plat_gic_driver_init(void) #endif } +static __inline void plat_gicr_exit_sleep(void) +{ + unsigned int val = mmio_read_32(PLAT_GICR_BASE + GICR_WAKER); + + /* + * 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 (val & WAKER_QSC_BIT) { + mmio_write_32(PLAT_GICR_BASE + GICR_WAKER, val & ~WAKER_SL_BIT); + /* Wait till the WAKER_QSC_BIT changes to 0 */ + while ((mmio_read_32(PLAT_GICR_BASE + GICR_WAKER) & WAKER_QSC_BIT) != 0U) + ; + } +} + void plat_gic_init(void) { + plat_gicr_exit_sleep(); gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos());