116 lines
3.5 KiB
C
116 lines
3.5 KiB
C
/*
|
|
* 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 <assert.h>
|
|
|
|
#include <arch_helpers.h>
|
|
#include <drivers/arm/arm_gicv3_common.h>
|
|
#include <drivers/arm/gicv3.h>
|
|
|
|
#include "gicv3_private.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);
|
|
|
|
/*
|
|
* If the GIC had power removed, the GICR_WAKER state will be reset.
|
|
* Since the GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits are cleared,
|
|
* we can exit early. This also prevents the following assert from
|
|
* erroneously triggering.
|
|
*/
|
|
if (!(gicr_read_waker(gicr_base) & WAKER_SL_BIT))
|
|
return;
|
|
|
|
/*
|
|
* 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)
|
|
;
|
|
}
|
|
|