| /* |
| * 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) |
| |
| #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) |
| |
| 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)); |
| } |
| |
| #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; |
| |
| 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_ */ |