arch: arm: cortex_a_r: add support for arm arch timer
This include make possible to use the arm_arch_timer on platform such as Cortex-A9 or Cortex-R7 which has support for ARM Global Timer. The global timer is a 64 bit incrementing counter, memory-mapped in the private memory region. Signed-off-by: Julien Massot <julien.massot@iot.bzh>
This commit is contained in:
parent
77dfc215a3
commit
f7e3f4f2d3
4 changed files with 131 additions and 0 deletions
|
@ -40,6 +40,7 @@
|
|||
#elif defined(CONFIG_CPU_CORTEX_R)
|
||||
#include <arch/arm/aarch32/cortex_a_r/cpu.h>
|
||||
#include <arch/arm/aarch32/cortex_a_r/sys_io.h>
|
||||
#include <arch/arm/aarch32/cortex_a_r/timer.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
126
include/arch/arm/aarch32/cortex_a_r/timer.h
Normal file
126
include/arch/arm/aarch32/cortex_a_r/timer.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2021 IoT.bzh
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_
|
||||
#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_
|
||||
|
||||
#ifdef CONFIG_ARM_ARCH_TIMER
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
|
||||
#include <drivers/timer/arm_arch_timer.h>
|
||||
#include <sys/device_mmio.h>
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARM_ARCH_TIMER_BASE DT_REG_ADDR_BY_IDX(ARM_TIMER_NODE, 0)
|
||||
#define ARM_ARCH_TIMER_IRQ ARM_TIMER_VIRTUAL_IRQ
|
||||
#define ARM_ARCH_TIMER_PRIO ARM_TIMER_VIRTUAL_PRIO
|
||||
#define ARM_ARCH_TIMER_FLAGS ARM_TIMER_VIRTUAL_FLAGS
|
||||
|
||||
#define TIMER_CNT_LOWER 0x00
|
||||
#define TIMER_CNT_UPPER 0x04
|
||||
#define TIMER_CTRL 0x08
|
||||
#define TIMER_ISR 0x0c
|
||||
#define TIMER_CMP_LOWER 0x10
|
||||
#define TIMER_CMP_UPPER 0x14
|
||||
|
||||
#define TIMER_IRQ_ENABLE BIT(2)
|
||||
#define TIMER_COMP_ENABLE BIT(1)
|
||||
#define TIMER_ENABLE BIT(0)
|
||||
|
||||
DEVICE_MMIO_TOPLEVEL_STATIC(timer_regs, ARM_TIMER_NODE);
|
||||
|
||||
#define TIMER_REG_GET(offs) (DEVICE_MMIO_TOPLEVEL_GET(timer_regs) + offs)
|
||||
|
||||
static ALWAYS_INLINE void arm_arch_timer_init(void)
|
||||
{
|
||||
DEVICE_MMIO_TOPLEVEL_MAP(timer_regs, K_MEM_CACHE_NONE);
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void arm_arch_timer_set_compare(uint64_t val)
|
||||
{
|
||||
uint32_t lower = (uint32_t)val;
|
||||
uint32_t upper = (uint32_t)(val >> 32);
|
||||
uint32_t ctrl;
|
||||
|
||||
/* Disable IRQ and comparator */
|
||||
ctrl = sys_read32(TIMER_REG_GET(TIMER_CTRL));
|
||||
ctrl &= ~(TIMER_COMP_ENABLE | TIMER_IRQ_ENABLE);
|
||||
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
|
||||
|
||||
sys_write32(lower, TIMER_REG_GET(TIMER_CMP_LOWER));
|
||||
sys_write32(upper, TIMER_REG_GET(TIMER_CMP_UPPER));
|
||||
|
||||
/* enable comparator back, let set_irq_mask enabling the IRQ again */
|
||||
ctrl |= TIMER_COMP_ENABLE;
|
||||
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void arm_arch_timer_enable(bool enable)
|
||||
{
|
||||
uint32_t ctrl;
|
||||
|
||||
ctrl = sys_read32(TIMER_REG_GET(TIMER_CTRL));
|
||||
if (enable) {
|
||||
ctrl |= TIMER_ENABLE;
|
||||
} else {
|
||||
ctrl &= ~TIMER_ENABLE;
|
||||
}
|
||||
|
||||
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void arm_arch_timer_set_irq_mask(bool mask)
|
||||
{
|
||||
uint32_t ctrl;
|
||||
|
||||
ctrl = sys_read32(TIMER_REG_GET(TIMER_CTRL));
|
||||
if (mask) {
|
||||
ctrl &= ~TIMER_IRQ_ENABLE;
|
||||
} else {
|
||||
ctrl |= TIMER_IRQ_ENABLE;
|
||||
sys_write32(1, TIMER_REG_GET(TIMER_ISR));
|
||||
}
|
||||
sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE uint64_t arm_arch_timer_count(void)
|
||||
{
|
||||
uint32_t lower;
|
||||
uint32_t upper, upper_saved;
|
||||
|
||||
/* To get the value from the Global Timer Counter register proceed
|
||||
* as follows:
|
||||
* 1. Read the upper 32-bit timer counter register.
|
||||
* 2. Read the lower 32-bit timer counter register.
|
||||
* 3. Read the upper 32-bit timer counter register again. If the value
|
||||
* is different to the 32-bit upper value read previously,
|
||||
* go back to step 2.
|
||||
* Otherwise the 64-bit timer counter value is correct.
|
||||
*/
|
||||
upper = sys_read32(TIMER_REG_GET(TIMER_CNT_UPPER));
|
||||
do {
|
||||
upper_saved = upper;
|
||||
lower = sys_read32(TIMER_REG_GET(TIMER_CNT_LOWER));
|
||||
upper = sys_read32(TIMER_REG_GET(TIMER_CNT_UPPER));
|
||||
} while (upper != upper_saved);
|
||||
|
||||
return ((uint64_t)upper) << 32 | lower;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
#endif /* CONFIG_ARM_ARCH_TIMER */
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ */
|
|
@ -23,6 +23,9 @@ extern "C" {
|
|||
#define CNTV_CTL_ENABLE ((1) << 0)
|
||||
#define CNTV_CTL_IMASK ((1) << 1)
|
||||
|
||||
static ALWAYS_INLINE void arm_arch_timer_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void arm_arch_timer_set_compare(uint64_t val)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue