Commit f7e3f4f2 authored by Julien Massot's avatar Julien Massot Committed by Anas Nashif
Browse files

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: default avatarJulien Massot <julien.massot@iot.bzh>
parent 77dfc215
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ int z_clock_driver_init(const struct device *device)

	IRQ_CONNECT(ARM_ARCH_TIMER_IRQ, ARM_ARCH_TIMER_PRIO,
		    arm_arch_timer_compare_isr, NULL, ARM_ARCH_TIMER_FLAGS);
	arm_arch_timer_init();
	arm_arch_timer_set_compare(arm_arch_timer_count() + CYC_PER_TICK);
	arm_arch_timer_enable(true);
	irq_enable(ARM_ARCH_TIMER_IRQ);
+1 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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_ */
+3 −0
Original line number Diff line number Diff line
@@ -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)
{