From 57f2d009fb198181c53f768233f76087ab918ce1 Mon Sep 17 00:00:00 2001 From: Andre Przywara <andre.przywara@arm.com> Date: Mon, 16 Sep 2024 16:11:50 +0100 Subject: [PATCH] fix(gicv3): do not assume redistributors are powered down When initialising a GICv3 compatible interrupt controller, we currently assume that the GIC is still in its reset state, which means the GICR_WAKER.ProcessorSleep bit is set. There is an "assert" in the GIC setup function to check this. However when using RESET_TO_BL31, there might be prior firmware running, and it might have used the GIC already. This is for instance the case on the Allwinner A523 SoC, where the BootROM initialises the GIC to use it when handling the built-in USB debug protocol. Drop the assert, which is not the right thing to do here anyway: it's not checking an internal state. Instead return early when the redistributor is already marked as active. Also keep waiting if ChildrenAsleep is unexpectedly set, but warn about this. This fixes booting TF-A on an Allwinner A523 SoC when using the USB debug mode. Change-Id: I5be9e1b0489d33b8371fff484e526483d5f3d937 Signed-off-by: Andre Przywara <andre.przywara@arm.com> --- drivers/arm/gic/v3/gicv3_helpers.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index b27debfa7..62ae0d276 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -35,11 +35,22 @@ uintptr_t gicv3_get_multichip_base(uint32_t spi_id, uintptr_t gicd_base) *****************************************************************************/ void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base) { + uint32_t waker = gicr_read_waker(gicr_base); + + /* Only try to mark it as awake when it is asleep. */ + if ((waker & WAKER_PS_BIT) == 0U) { + return; + } + /* - * The WAKER_PS_BIT should be changed to 0 - * only when WAKER_CA_BIT is 1. + * ProcessorSleep must only be changed when ChildrenAsleep is 1. + * If PS is 1 and CA isn't, wait for that to happen, but warn. */ - assert((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U); + if ((waker & WAKER_CA_BIT) == 0U) { + WARN("GICR_WAKER.ChildrenAsleep unexpectedly set, waiting...\n"); + while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U) { + } + } /* Mark the connected core as awake */ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT);