drivers: timer: arm_arch_timer: Workaround for Cortex-A9 erratum 740657

Modification of the ARM architected timer driver and its configuration
data in order to address an erratum which exists at least in the Cor-
tex-A9 CPU, and which can also be observed in the QEMU implementation
of the Cortex-A9.

Comp.: ARM Cortex-A9 processors Software Developer Errata Notice
ARM document ID032315
Erratum 740657

This erratum causes a spurious interrupt pending indication with the
interrupt controller if no new compare value is written within the
timer ISR before the interrupt is cleared. This is usually the case
in tickless mode. If the spurious interrupt is not prevented, the
timer ISR will be called twice, but on second execution, the pending
flag is not set within the timer's register space. Not handling this
issue will lead to erratic tick announcements to the kernel.

Signed-off-by: Immo Birnbaum <Immo.Birnbaum@weidmueller.com>
This commit is contained in:
Immo Birnbaum 2021-07-15 11:41:34 +02:00 committed by Carles Cufí
commit 315ad1d6e6
3 changed files with 76 additions and 0 deletions

View file

@ -35,6 +35,8 @@ extern "C" {
#define TIMER_COMP_ENABLE BIT(1)
#define TIMER_ENABLE BIT(0)
#define TIMER_ISR_EVENT_FLAG BIT(0)
DEVICE_MMIO_TOPLEVEL_STATIC(timer_regs, ARM_TIMER_NODE);
#define TIMER_REG_GET(offs) (DEVICE_MMIO_TOPLEVEL_GET(timer_regs) + offs)
@ -63,6 +65,30 @@ static ALWAYS_INLINE void arm_arch_timer_set_compare(uint64_t val)
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
}
#if defined(CONFIG_ARM_ARCH_TIMER_ERRATUM_740657)
/*
* R/W access to the event flag register is required for the timer errata
* 740657 workaround -> comp. ISR implementation in arm_arch_timer.c.
* This functionality is not present in the aarch64 implementation of the
* ARM global timer access functions.
*
* comp. ARM Cortex-A9 processors Software Developers Errata Notice,
* ARM document ID032315.
*/
static ALWAYS_INLINE uint8_t arm_arch_timer_get_int_status(void)
{
return (uint8_t)(sys_read32(TIMER_REG_GET(TIMER_ISR)) & TIMER_ISR_EVENT_FLAG);
}
static ALWAYS_INLINE void arm_arch_timer_clear_int_status(void)
{
sys_write32(TIMER_ISR_EVENT_FLAG, TIMER_REG_GET(TIMER_ISR));
}
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
static ALWAYS_INLINE void arm_arch_timer_enable(bool enable)
{
uint32_t ctrl;