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:
parent
a69cd66b6e
commit
315ad1d6e6
3 changed files with 76 additions and 0 deletions
|
@ -120,6 +120,17 @@ DT_COMPAT_ARM_V7M_SYSTICK := arm,armv7m-systick
|
|||
DT_COMPAT_ARM_V8M_SYSTICK := arm,armv8m-systick
|
||||
DT_COMPAT_ARM_V8_1M_SYSTICK := arm,armv8.1m-systick
|
||||
|
||||
config ARM_ARCH_TIMER_ERRATUM_740657
|
||||
bool "ARM architected timer is affected by ARM erratum 740657"
|
||||
depends on ARM_ARCH_TIMER
|
||||
help
|
||||
This option indicates that the ARM architected timer as implemented
|
||||
in the target hardware is affected by the ARM erratum 740657 (comp.
|
||||
ARM Cortex-A9 processors Software Developers Errata Notice, ARM
|
||||
document ID032315) which leads to an additional, spurious interrupt
|
||||
indication upon every actual timer interrupt. This option activates
|
||||
the workaround for the erratum within the timer driver.
|
||||
|
||||
config CORTEX_M_SYSTICK
|
||||
bool "Cortex-M SYSTICK timer"
|
||||
depends on CPU_CORTEX_M_HAS_SYSTICK
|
||||
|
|
|
@ -24,6 +24,24 @@ static void arm_arch_timer_compare_isr(const void *arg)
|
|||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
|
||||
#ifdef CONFIG_ARM_ARCH_TIMER_ERRATUM_740657
|
||||
/*
|
||||
* Workaround required for Cortex-A9 MPCore erratum 740657
|
||||
* comp. ARM Cortex-A9 processors Software Developers Errata Notice,
|
||||
* ARM document ID032315.
|
||||
*/
|
||||
|
||||
if (!arm_arch_timer_get_int_status()) {
|
||||
/*
|
||||
* If the event flag is not set, this is a spurious interrupt.
|
||||
* DO NOT modify the compare register's value, DO NOT announce
|
||||
* elapsed ticks!
|
||||
*/
|
||||
k_spin_unlock(&lock, key);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
|
||||
|
||||
uint64_t curr_cycle = arm_arch_timer_count();
|
||||
uint32_t delta_ticks = (uint32_t)((curr_cycle - last_cycle) / CYC_PER_TICK);
|
||||
|
||||
|
@ -39,8 +57,29 @@ static void arm_arch_timer_compare_isr(const void *arg)
|
|||
arm_arch_timer_set_irq_mask(false);
|
||||
} else {
|
||||
arm_arch_timer_set_irq_mask(true);
|
||||
#ifdef CONFIG_ARM_ARCH_TIMER_ERRATUM_740657
|
||||
/*
|
||||
* In tickless mode, the compare register is normally not
|
||||
* updated from within the ISR. Yet, to work around the timer's
|
||||
* erratum, a new value *must* be written while the interrupt
|
||||
* is being processed before the interrupt is acknowledged
|
||||
* by the handling interrupt controller.
|
||||
*/
|
||||
arm_arch_timer_set_compare(~0ULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the event flag so that in case the erratum strikes (the timer's
|
||||
* vector will still be indicated as pending by the GIC's pending register
|
||||
* after this ISR has been executed) the error will be detected by the
|
||||
* check performed upon entry of the ISR -> the event flag is not set,
|
||||
* therefore, no actual hardware interrupt has occurred.
|
||||
*/
|
||||
arm_arch_timer_clear_int_status();
|
||||
#else
|
||||
}
|
||||
#endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
|
||||
sys_clock_announce(delta_ticks);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue